I'm develop a game with starling-framework.my problem is how to detect all tween is complete when I add a set of elements into juggler.
current my plan is
while(some_condition){ //allocate a set of tween
var tween=createTween(tweenCount++);
tween.onComplete=function(){
tweenCount--;
}
}
function checkComplete(){
if(tweenCount==0)
doStuff();
else
setTimeout(checkComplete,1000);
}
and there is any better solution ? thanks for your time!
update
write a simple class to solve this ,seems like better
public class TweenMonitor
{
public function TweenMonitor()
{
throw new Error('static class');
}
private static var refDict:Dictionary = new Dictionary();
public static function monit(tweens:Vector.<Tween>,onAllFinish:Function,id:String='$default$'):void
{
for (var i:int = 0; i < tweens.length; i++)
{
var tween:Tween = tweens[i];
if (tween == null)
continue;
if (refDict[id] == null) {
refDict[id] = 1;
}else
refDict[id]++;
tween.addEventListener(Event.REMOVE_FROM_JUGGLER,function (e:Event):void
{
refDict[id]--;
if (refDict[id] == 0)
onAllFinish && onAllFinish();
});
}
}
}
You simply need the onComplete property of Tween Class (Starling Framework)
Here is an Example :
function addTween() {
var tween:Tween = new Tween(object, 2.0, Transitions.EASE_IN_OUT);
tween.animate("x", object.x + 50);
tween.animate("rotation", deg2rad(45));
tween.fadeTo(0);
tween.onComplete = tween_complete;
Starling.juggler.add(tween);
}
function tween_complete() {
// Handle Tween Complete Action Here
}
EDIT
In case of multiple tweens, you probably could do better by attaching a timer class instead of settimeout:
while(some_condition){ //allocate a set of tween
var tween=createTween(tweenCount++);
tween.onComplete = function() { tweenCount--; }
}
var timer : Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER,update);
timer.start();
function update(e) {
if(tweenCount > 0) return;
timer.stop();
timer = null;
doStuff();
}
I would have done like this:
OnComplete = tweenDone;
...
function tweenDone() {
TweenCount--;
If(TweenCount == 0) doStuff();
}
Wrote this on a cell phone so I had to take a lot of shortcuts, if you need more info, leave a comment!
Related
I am new to actionscript and I am trying to make a "cheat" way of completing a sliding puzzle where when I click the [s] key it calls a solve puzzle function which makes a for loop put all the puzzle pieces in the correct location. This function must call a for loop, those were the instructions I was given. Could anyone help me understand the code that I need to make this happen. I have already made the function and it does properly call when I hit the s key but everything past that doesn't seem to make the code actually move the pieces. Thank you for any help I can get.
package {
import flash.display.*;
import flash.events.*;
import flash.net.URLRequest;
import flash.geom.*;
import flash.utils.Timer;
public class SlidingPuzzle extends MovieClip {
// space between pieces and offset
static const pieceSpace:Number = 2;
static const horizOffset:Number = 50;
static const vertOffset:Number = 50;
// number of pieces
static const numPiecesHoriz:int = 5;
static const numPiecesVert:int = 5;
// random shuffle steps
static const numShuffle:int = 200;
// animation steps and time
static const slideSteps:int = 10;
static const slideTime:int = 250;
// size of pieces
private var pieceWidth:Number;
private var pieceHeight:Number;
// game pieces
private var puzzleObjects:Array;
// tracking moves
private var blankPoint:Point;
private var slidingPiece:Object;
private var slideDirection:Point;
private var slideAnimation:Timer;
public function startSlidingPuzzle() {
// blank spot is the bottom right
blankPoint = new Point(numPiecesHoriz-1,numPiecesVert-1);
// load the bitmap
loadBitmap("oceanshore.jpg");
// event to complete the puzzle for you.
stage.addEventListener(KeyboardEvent.KEY_UP, solvePuzzle);
}
// get the bitmap from an external source
public function loadBitmap(bitmapFile:String) {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingDone);
var request:URLRequest = new URLRequest(bitmapFile);
loader.load(request);
}
// bitmap done loading, cut into pieces
public function loadingDone(event:Event):void {
// create new image to hold loaded bitmap
var image:Bitmap = Bitmap(event.target.loader.content);
pieceWidth = image.width/numPiecesHoriz;
pieceHeight = image.height/numPiecesVert;
// cut into puzzle pieces
makePuzzlePieces(image.bitmapData);
// shuffle them
shufflePuzzlePieces();
}
// cut bitmap into pieces
public function makePuzzlePieces(bitmapData:BitmapData) {
puzzleObjects = new Array();
for(var x:uint=0;x<numPiecesHoriz;x++) {
for (var y:uint=0;y<numPiecesVert;y++) {
// skip blank spot
if (blankPoint.equals(new Point(x,y))) continue;
// create new puzzle piece bitmap and sprite
var newPuzzlePieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth,pieceHeight));
newPuzzlePieceBitmap.bitmapData.copyPixels(bitmapData,new Rectangle(x*pieceWidth,y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0));
var newPuzzlePiece:Sprite = new Sprite();
newPuzzlePiece.addChild(newPuzzlePieceBitmap);
addChild(newPuzzlePiece);
// set location
newPuzzlePiece.x = x*(pieceWidth+pieceSpace) + horizOffset;
newPuzzlePiece.y = y*(pieceHeight+pieceSpace) + vertOffset;
// create object to store in array
var newPuzzleObject:Object = new Object();
newPuzzleObject.currentLoc = new Point(x,y);
newPuzzleObject.homeLoc = new Point(newPuzzlePiece.x,newPuzzlePiece.y);
newPuzzleObject.piece = newPuzzlePiece;
newPuzzlePiece.addEventListener(MouseEvent.CLICK,clickPuzzlePiece);
puzzleObjects.push(newPuzzleObject);
}
}
}
//make the puzzle solve itself
public function solvePuzzle(evt:KeyboardEvent)
{
if (evt.keyCode == 83)
{
for(var i:int = 0; i<puzzleObjects.length; i++)
{
}
}
}
// make a number of random moves
public function shufflePuzzlePieces() {
for(var i:int=0;i<numShuffle;i++) {
shuffleRandom();
}
}
// random move
public function shuffleRandom() {
// loop to find valid moves
var validPuzzleObjects:Array = new Array();
for(var i:uint=0;i<puzzleObjects.length;i++) {
if (validMove(puzzleObjects[i]) != "none") {
validPuzzleObjects.push(puzzleObjects[i]);
}
}
// pick a random move
var pick:uint = Math.floor(Math.random()*validPuzzleObjects.length);
movePiece(validPuzzleObjects[pick],false);
}
public function validMove(puzzleObject:Object): String {
// is the blank spot above
if ((puzzleObject.currentLoc.x == blankPoint.x) &&
(puzzleObject.currentLoc.y == blankPoint.y+1)) {
return "up";
}
// is the blank spot below
if ((puzzleObject.currentLoc.x == blankPoint.x) &&
(puzzleObject.currentLoc.y == blankPoint.y-1)) {
return "down";
}
// is the blank to the left
if ((puzzleObject.currentLoc.y == blankPoint.y) &&
(puzzleObject.currentLoc.x == blankPoint.x+1)) {
return "left";
}
// is the blank to the right
if ((puzzleObject.currentLoc.y == blankPoint.y) &&
(puzzleObject.currentLoc.x == blankPoint.x-1)) {
return "right";
}
// no valid moves
return "none";
}
// puzzle piece clicked
public function clickPuzzlePiece(event:MouseEvent) {
// find piece clicked and move it
for(var i:int=0;i<puzzleObjects.length;i++) {
if (puzzleObjects[i].piece == event.currentTarget) {
movePiece(puzzleObjects[i],true);
break;
}
}
}
// move a piece into the blank space
public function movePiece(puzzleObject:Object, slideEffect:Boolean) {
// get direction of blank space
switch (validMove(puzzleObject)) {
case "up":
movePieceInDirection(puzzleObject,0,-1,slideEffect);
break;
case "down":
movePieceInDirection(puzzleObject,0,1,slideEffect);
break;
case "left":
movePieceInDirection(puzzleObject,-1,0,slideEffect);
break;
case "right":
movePieceInDirection(puzzleObject,1,0,slideEffect);
break;
}
}
// move the piece into the blank spot
public function movePieceInDirection(puzzleObject:Object, dx,dy:int, slideEffect:Boolean) {
puzzleObject.currentLoc.x += dx;
puzzleObject.currentLoc.y += dy;
blankPoint.x -= dx;
blankPoint.y -= dy;
// animate or not
if (slideEffect) {
// start animation
startSlide(puzzleObject,dx*(pieceWidth+pieceSpace),dy*(pieceHeight+pieceSpace));
} else {
// no animation, just move
puzzleObject.piece.x = puzzleObject.currentLoc.x*(pieceWidth+pieceSpace) + horizOffset;
puzzleObject.piece.y = puzzleObject.currentLoc.y*(pieceHeight+pieceSpace) + vertOffset;
}
}
// set up a slide
public function startSlide(puzzleObject:Object, dx, dy:Number) {
if (slideAnimation != null) slideDone(null);
slidingPiece = puzzleObject;
slideDirection = new Point(dx,dy);
slideAnimation = new Timer(slideTime/slideSteps,slideSteps);
slideAnimation.addEventListener(TimerEvent.TIMER,slidePiece);
slideAnimation.addEventListener(TimerEvent.TIMER_COMPLETE,slideDone);
slideAnimation.start();
}
// move one step in slide
public function slidePiece(event:Event) {
slidingPiece.piece.x += slideDirection.x/slideSteps;
slidingPiece.piece.y += slideDirection.y/slideSteps;
}
// complete slide
public function slideDone(event:Event) {
slidingPiece.piece.x = slidingPiece.currentLoc.x*(pieceWidth+pieceSpace) + horizOffset;
slidingPiece.piece.y = slidingPiece.currentLoc.y*(pieceHeight+pieceSpace) + vertOffset;
slideAnimation.stop();
slideAnimation = null;
// check to see if puzzle is complete now
if (puzzleComplete()) {
clearPuzzle();
gotoAndStop("gameover");
}
}
// check to see if all pieces are in place
public function puzzleComplete():Boolean {
for(var i:int=0;i<puzzleObjects.length;i++) {
if (!puzzleObjects[i].currentLoc.equals(puzzleObjects[i].homeLoc)) {
return false;
}
}
return true;
}
// remove all puzzle pieces
public function clearPuzzle() {
for (var i in puzzleObjects) {
puzzleObjects[i].piece.removeEventListener(MouseEvent.CLICK,clickPuzzlePiece);
removeChild(puzzleObjects[i].piece);
}
puzzleObjects = null;
}
}
First, program must know where to place the objects, for them to placed correctly. And best way to do it, is to record piece's initial positions.
Before you set piece's new location, create the Object and take it's initial location.
newPuzzleObject.initialLoc = new Point(newPuzzlePiece.x,newPuzzlePiece.y);
Object creation must come before this part, before piece's initial position changed;
// set location
newPuzzlePiece.x = x*(pieceWidth+pieceSpace) + horizOffset;
newPuzzlePiece.y = y*(pieceHeight+pieceSpace) + vertOffset;
And at the solvePuzzle, place them all back to their initial location.
for(i:uint; i < puzzleObjects.length; i++)
{
puzzleObjects[i].x = puzzleObjects[i].initialLoc.x;
puzzleObjects[i].y = puzzleObjects[i].initialLoc.y;
}
My code is:
for (var i:int=1; i <= 12; i++) {
MovieClip(getChildByName('mouse' + '_' + i)).addEventListener(MouseEvent.CLICK, chooseTool);
}
function chooseTool(e:MouseEvent):void {
Mouse.hide();
var cursor:MovieClip = new "here is e.target.name"();
addChild(cursor);
stage.addEventListener(MouseEvent.MOUSE_MOVE, follow);
}
function follow(e:MouseEvent):void {
cursor.x=mouseX;
cursor.y=mouseY;
}
How to use "e.target.name" for name ?
Should become something like:
1) Click on button with name mouse_4
2) Function chooseTool create new MovieClip with name mouse_4();
example: var cursor:MovieClip = new mouse_4();
You can do it by using getDefinitionByName (Adobe documentation: getDefinitionByName)
for (var i:int=1; i <= 12; i++) {
MovieClip(getChildByName('mouse' + '_' + i)).addEventListener(MouseEvent.CLICK, chooseTool);
}
function chooseTool(e:MouseEvent):void {
Mouse.hide();
var o:Object = getDefinitionByName(e.target.name);
// ^ Gets a reference to the class object based on a string
if(o == null) throw new Error("Unable to find class " + e.target.name);
var c:Class = o as Class;
var cursor:MovieClip = new c() as MovieClip;
addChild(cursor);
stage.addEventListener(MouseEvent.MOUSE_MOVE, follow);
}
function follow(e:MouseEvent):void {
cursor.x=mouseX;
cursor.y=mouseY;
}
But this feels very ill structured way of doing it. Instead I would use a factory method (Factory pattern on Wikipedia)
for (var i:int=1; i <= 12; i++) {
MovieClip(getChildByName('mouse' + '_' + i)).addEventListener(MouseEvent.CLICK, chooseTool);
}
function chooseTool(e:MouseEvent):void {
Mouse.hide();
var cursor:MovieClip = getCursor(e.target);
addChild(cursor);
stage.addEventListener(MouseEvent.MOUSE_MOVE, follow);
}
function follow(e:MouseEvent):void {
cursor.x=mouseX;
cursor.y=mouseY;
}
function getCursor(target:MovieClip):MovieClip
{
switch(target.name)
{
case "cursor_4":
return new cursor_4();
default:
return new default_mouse();
}
}
You can't do it like that. That is not realy a name would be a new class/type. The solution is to extend the MovieClip and pass that name as a parameter . I do not know what you want to achieve but this is a good way to start.
class MyClip extends MovieClip
{
public var name:String="";
public function MyClip(name:String)
{
super();
this.name=name;
}
}
}
The code will look something like that and you can add all the logic related with this type inside this class.
You can't Instantiate like this new "e.target.name"();
But if you want to take the reference of target,you can try this.
var cursor:MovieClip =e.target as MovieClip;
you cannot modify the name property of cursor.
I have two movie clips in the library with linkage.
on the stage I have two buttons - each load a movie clip to a specific mc target on the stage.
I also have a third button that removes the mc target, to clear the stage.
I want to know how can I change the code in AS3 so the loaded movie clips will not show at the same time, but swap each other, like I used to use depth in AS2.
This is the code:
var myIgool = new igool ();
var myRibooa = new ribooa ();
loadigool.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_3);
function fl_MouseClickHandler_3(event:MouseEvent):void
{
mc_all.addChild (myIgool);
}
loadribooa.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_4);
function fl_MouseClickHandler_4(event:MouseEvent):void
{
mc_all.addChild (myRibooa);
}
unloadall.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_6);
function fl_MouseClickHandler_6(event:MouseEvent):void
{
removeChild(mc_all);
;
}
I would recommend something like this:
var myIgool = new igool ();
var myRibooa = new ribooa ();
mc_all.addChild(myIgool);
mc_all.addChild(myRibooa);
myIgool.visible = false;
myRibooa.visible = false;
loadigool.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_3);
function fl_MouseClickHandler_3(event:MouseEvent):void
{
myIgool.visible = true;
myRibooa.visible = false;
}
loadribooa.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_4);
function fl_MouseClickHandler_4(event:MouseEvent):void
{
myIgool.visible = false;
myRibooa.visible = true;
}
unloadall.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_6);
function fl_MouseClickHandler_6(event:MouseEvent):void
{
myIgool.visible = false;
myRibooa.visible = false;
}
But if you really want to swap, you could also do the following, however I recommend setting the visible flag as it's more efficient rather than covering something up that wouldn't need to draw.
loadigool.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_3);
function fl_MouseClickHandler_3(event:MouseEvent):void
{
if (myIgool.parent != mc_all)
{
mc_all.addChild(myIgool);
}
else
{
mc_all.setChildIndex(myIgool, mc_all.numChildren - 1);
}
}
loadribooa.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler_4);
function fl_MouseClickHandler_4(event:MouseEvent):void
{
if (myRibooa.parent != mc_all)
{
mc_all.addChild(myRibooa);
}
else
{
mc_all.setChildIndex(myRibooa, mc_all.numChildren - 1);
}
}
I have done a drag and match flash stuff by using Actionscipt2.0, but now I need to change it to 3.0. After I changed it, the flash can no longer drag the stuffs, can anyone please take a look at the code to see which part I was converting it wrong. Thanks.
Actionscript 2.0 version:
stop();
var randomPositionFrame = int(Math.random()*9)+1;
content_mc.gotoAndStop(randomPositionFrame);
for(var i=1; i<=5; i++){
eval("content_mc.matching_term_"+i)._alpha = 0;
eval("content_mc.matching_term_"+i).onPress = function(){
if(this._currentframe == 1){
this.startDrag();
}
}
eval("content_mc.matching_term_"+i).onRelease = onMouseUp = function(){
this.stopDrag();
}
eval("content_mc.matching_desc_"+i)._alpha = 0;
eval("content_mc.matching_desc_"+i).onPress = function(){
if(this._currentframe == 1){
this.startDrag();
}
}
eval("content_mc.matching_desc_"+i).onRelease = onMouseUp = function(){
this.stopDrag();
}
}
Actionscript 3.0 version:
stop();
var randomPositionFrame = int(Math.random()*9)+1;
content_mc.gotoAndStop(randomPositionFrame);
for(var i=1; i<=5; i++){
this["content_mc.matching_term_"+i]._alpha = 0;
this["content_mc.matching_term_"+i].addEventListener(MouseEvent.MOUSE_DOWN,function():void {
if(this._currentframe == 1){
this.startDrag();
}
}
);
this["content_mc.matching_term_"+i].addEventListener(MouseEvent.MOUSE_UP,function():void {
stage.addEventListener(MouseEvent.MOUSE_UP, doMouseUp, false, 0, true);
function doMouseUp($evt:MouseEvent):void
{
this.stopDrag();
}
}
);
this["content_mc.matching_desc_"+i]._alpha = 0;
this["content_mc.matching_term_"+i].addEventListener(MouseEvent.MOUSE_DOWN,function():void {
if(this._currentframe == 1){
this.startDrag();
}
}
);
this["content_mc.matching_desc_"+i].addEventListener(MouseEvent.MOUSE_UP,function():void {
this.stopDrag();
}
);
}
In your Mouse Listener you have to get the target/object from the event. Meaning the target you applied your listener to.
Create two listener functions and apply them to your addEventListener call:
function mouseDownHandler(e:MouseEvent):void
{
var object = e.target;
object.startDrag();
}
function mouseUpHandler(e:MouseEvent):void
{
var obj = e.target;
obj.stopDrag();
}
Use addEventListener like this:
yourObj.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
yourObj.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
This won't work
this["content_mc.matching_term_"+i]
You need to talk to each object separately. So first this then content_mc.
this.content_mc["matching_term_"+i]
Might help a little.
I have a simple actionscript function
var string:String = "TEXT REMOVED";
var myArray:Array = string.split("");
addEventListener(Event.ENTER_FRAME, frameLooper);
function frameLooper(event:Event):void {
if(myArray.length > 0) {
text1.appendText(myArray.shift());
}else{
removeEventListener(Event.ENTER_FRAME, frameLooper);
}
}
And I want to have it sleep after calling the framelooper so it is a little bit slower. How could I do this?
btw, I'm fairly new and found this code on a tutorial, it's a text typing effect, if there is a better way of doing this please let me know.
Use a Timer:
var string:String = "TEXT REMOVED";
var myArray:Array = string.split("");
var timer : Timer = new Timer (1000, myArray.length);
timer.addEventListener (TimerEvent.TIMER, frameLooper);
timer.start();
function frameLooper(event:Event):void {
text1.appendText(myArray.shift());
}
This will execute the frameLooper on every second for exactly as many times as the length of the array.
I'm not saying this is better than the timer method, just an option
var string:String = "TEXT REMOVED";
var myArray:Array = string.split("");
addEventListener(Event.ENTER_FRAME, frameLooper);
const WAIT_TIME:int = 10;
var i:int = 0;
function frameLooper(event:Event):void {
if(myArray.length > 0) {
if(i==0){
trace(myArray.shift());
i = WAIT_TIME;
};
} else {
removeEventListener(Event.ENTER_FRAME, frameLooper);
}
i--;
}