PDA

View Full Version : Trouble with tweenlite used in for loop


bobaloo1349
01-02-2009, 01:53 PM
I'm developing a board game in AS2, using tweenlite to move the players after a dice roll. Each player is a human character facing different directions in its timeline, and a walking animation of each character in that timeline. To keep the walking relatively smooth, I have the player movement set up in a FOR LOOP to iterate x times (the dice roll = moveCount) and walk from space to space, turning direction if the board direction changes.

The only challenge is when the dice rolls a number higher than 1, the player piece sort of "scoots" directly to that next space (kind of running in air), not stepping thru the tween the required number of times.

Here's a simplified version of my code:

//This is part of the function that calls the movePlayer function, which contains the TweenLite.to

//step the number of spaces on this roll
for (var i:Number = 1; i <= moveCount; i++)
{
movePlayer(playerID, startNum, nextNum);
startNum++;
nextNum++;
}*/



function movePlayer(playerID:Number, startNum:Number, nextNum:Number):Void {

//move the current player, exec walk motion while tweening
TweenLite.to (currentPlayer, 2,
{
_x:(thePoint.x)-offsetX,
_y:(thePoint.y)-offsetY,
delay:.25,
onStart:doTheWalk,
onStartParams:[currentPlayer, walkDir],
onComplete:doTheRest,
onCompleteParams:[currentPlayer, restDir]
}
);

}

//rotate player into exit position
function doTheExit(thePlayer:MovieClip, exitDirection:String):Void
{
thePlayer.gotoAndPlay(exitDirection);
}


//player walk animation
function doTheWalk(thePlayer:MovieClip, walkDirection:String):Void
{
thePlayer.gotoAndPlay(walkDirection);
}

//rotate player into rest position
function doTheRest(thePlayer:MovieClip, restDirection:String):Void
{
thePlayer.gotoAndPlay(restDirection);
}


I've tried using the overwrite property to prevent the next tween from running before the current one finishes to no avail. I've also tried using a simple timing loop within the for...next code, that doesn't work either.

Any ideas what I'm missing here? I'm pulling my hair out (and I don't have too much of that left).

rrh
01-02-2009, 03:13 PM
Create an array and push all of these to it:
{
_x:(thePoint.x)-offsetX,
_y:(thePoint.y)-offsetY,
delay:.25,
onStart:doTheWalk,
onStartParams:[currentPlayer, walkDir],
onComplete:doTheRest,
onCompleteParams:[currentPlayer, restDir]
}

Then, inside doTheRest, test to see if the array is empty, if it isn't, shift another entry off the array and tween to that entry.

invision-studios
01-04-2009, 05:33 AM
RRH,

Are you suggesting I store all the parameters for the tween in an array, then pull those parameters into the tweenlite code? I didn't think that was possible.

Can you give me a little more detail? I'm not sure I understand what you're suggesting in your reply.

rrh
01-04-2009, 05:04 PM
Array.push(object) pushes the object onto the end of the array.
Array.shift() pulls an object off the start of the array. Use this instead of Array.pop() because pop would give you the reverse order from how you put them into the Array.

You'll also need to actually vary the _x and _y value for each step. I notice now that the for loop doesn't actually change any of the values passed to the .to() call. It changes two of the three parameters passed to the movePlayer() function but none of those parameters are use in the .to() call. Obviously if you just use the same values five times in a row, that's not going to make a series of steps, that's going to make one step, followed by four turns of standing still.

invision-studios
01-04-2009, 11:29 PM
The intent of the "startNum++;" and "nextNum++;" statements is to increment the space count after each calling of the advancePlayer function.

Shouldn't the FOR loop increment those every time it loops back thru?

rrh
01-05-2009, 12:25 AM
I don't see any function called advancePlayer. I do see one called movePlayer.

When I said It changes two of the three parameters passed to the movePlayer() function startNum and nextNum were the two parameters I was referring to. But notice I also said but none of those parameters are use[d] in the .to() call.

So, yes they are being incremented, but why does it matter if they aren't being used?

invision-studios
01-05-2009, 01:37 AM
Sorry, I meant movePlayer function. Actually, I oversimplified the code for this forum.

The actual move of the player is in the _x and _y coordinates of the to. call. The doTheWalk() function is called at the beginning of the to. call and runs while the player is moving across the board to simulate leg movement.

The FOR loop should call the to. function, move the player a single space (while moving his legs in place with the doTheWalk() function), then return to the FOR loop. It should then increment the nextSpace until the move count is complete.

Instead, the player floats directly to the final space in the move, rather than following the path of the game board one space at a time.


Here's the real code. Keep in mind there are four possible players with their own quadrants on each board space, so a lot of this is calculating which quad each player should land on. Spaces are movieClips instances named "space01" etc.

I appreciate your time looking at this, rrh.



function advancePlayer(playerID:Number, moveCount:Number):Void
{
//current player location
var currentLocation:String = currentSpace[playerID];

//extract number from currentLocation
var origNum:String = substring(currentLocation, 6, 2);

//add the moveCount to currentLocation
var newNum:Number = Number(origNum) + Number(moveCount);

//build string for the new space, store in array for next move
var newSpace:String;
if (newNum < 10)
{
newSpace = "space0" + newNum;
}
else
{
newSpace = "space" + newNum;
}
currentSpace[playerID] = newSpace; //store in Array

//build var to step forward one from current space
var startNum:Number = Number(origNum);
var nextNum:Number = Number(origNum) + 1;

//step the number of spaces on this roll
for (var i:Number = 1; i <= moveCount; i++)
{
movePlayer(playerID,startNum,nextNum);
startNum++;
nextNum++;
}
}


///////////////////////////////// physically move player object
function movePlayer(playerID:Number, startNum:Number, nextNum:Number):Void
{

//map playerID numbers to MC names
var playerName:String;
switch (playerID)
{
case 1 :
playerName = "player2_mc";
break;
case 2 :
playerName = "player3_mc";
break;
case 3 :
playerName = "player4_mc";
break;
default :
playerName = "player1_mc";
break;
}

//build string for the spaces
var startString:String;
if (startNum < 10)
{
startString = "0" + startNum;
}
else
{
startString = String(startNum);
}

var nextSpace:String;
if (nextNum < 10)
{
nextSpace = "space0" + nextNum;
}
else
{
nextSpace = "space" + nextNum;

}
// build location expression to determine new space's x/y coordinates (in proper quadrant)
var theSpace:MovieClip = eval(nextSpace + ".quad" + Number(playerID));

//create object to mark x/y coord of quadrant
var thePoint:Object = {x:(theSpace._x), y:theSpace._y};

//convert playerName string to MovieClip object
var currentPlayer:MovieClip = eval(playerName);

//map local x/y to stage x/y
theSpace.localToGlobal(thePoint);

//coordinate adjustments for proper placement (bug in localToGlobal?)
switch (playerID)
{
case 1 :
offsetX = 30;
offsetY = 24;
break;
case 2 :
offsetX = 19;
offsetY = 12;
break;
case 3 :
offsetX = 49;
offsetY = 12;
break;
default :
offsetX = 0;
offsetY = 29;
break;
}
//rotate player - id current space
var xID:String = "exit" + startString;

//build string for the rest direction
var r:Number = Number(startString);
r++;
var rID:String;
if (r < 10)
{
rID = "rest0" + r;
}
else
{
rID = "rest" + r;
}

//get exit directions from spaceDirection object
var exitDir:String = spaceDirection[xID];
var restDir:String = spaceDirection[rID];
doTheExit(currentPlayer,exitDir);

//create pointer to walk animation in player movieclip
var walkDir:String = "walk_" + exitDir;

//move the current player, exec walk motion while tweening
TweenLite.to(currentPlayer,2,{
_x:(thePoint.x) - offsetX,
_y:(thePoint.y) - offsetY,
delay:.25,
onStart:doTheWalk,
onStartParams:[currentPlayer, walkDir, nextSpace, playerID],
onComplete:doTheRest,
onCompleteParams:[currentPlayer,
restDir],
overWrite:0});
}

//rotate player into exit position
function doTheExit(thePlayer:MovieClip, exitDirection:String):Void
{
thePlayer.gotoAndPlay(exitDirection);
//trace("doing the exit!!");
}

//player walk animation
function doTheWalk(thePlayer:MovieClip, walkDirection:String, nextSpace:String, playerID:Number):Void
{
thePlayer.gotoAndPlay(walkDirection);
adjustPlayerDepth(thePlayer,nextSpace,playerID);
//trace("doing the walk!!");
}
//rotate player into rest position
function doTheRest(thePlayer:MovieClip, restDirection:String):Void
{
thePlayer.gotoAndPlay(restDirection);
//trace("doing the rest!!");
trace(thePlayer + " depth: " + thePlayer.getDepth());
}

rrh
01-05-2009, 02:45 AM
Okay. That makes sense. We do sometimes get people who haven't fully grasped how a loop or function call works.

So back to my original idea, yeah, you can store anything in an array, so you could easily enough push the { object } into the array and then in your onComplete function, you pull one from the array, and tween there. (And if the array's length==0 then it's finished moving.)


Another approach is you could build a nested object from the last square backwards and then pass that through the parameters:
var lastStep:Object = {
_x:(thePoint.x)-offsetX,
_y:(thePoint.y)-offsetY,
delay:.25,
onStart:doTheWalk,
onStartParams:[currentPlayer, walkDir],
onComplete:doTheRest,
onCompleteParams:[currentPlayer, restDir]
}

var otherStep:Object = lastStep;

for (from second last step backwards to first step) {
calculate position for another step
otherStep = {
_x:(thePoint.x)-offsetX,
_y:(thePoint.y)-offsetY,
delay:.25,
onStart:doTheWalk,
onStartParams:[currentPlayer, walkDir],
onComplete:doNextStep,
onCompleteParams:[currentPlayer, otherStep]
}
}

doNextStep(currentPlayer,otherStep);



Then in your doNextStep function, you call the TweenLite.to()

invision-studios
01-07-2009, 07:41 AM
FWIW, the script actually pulls the x y values from the board pieces, which are instances of a movieclip w/embedded instances of the quadrants movieclip. I was trying to be efficient... and thinking there might be changes made to the board layout in the future. Since all the space instances are named, the player always knows which space to go to next.

I just don't see what advantage there would be to having to create an array for the entire game board at this point.

One thing I haven't gotten answered here or on any other forum about this issue -- is my logic sound? It sure seems like the tweenlite tweens are all firing consecutively without actually running back thru the for loop. Even with a delay parameter set in tweenlite, even with the overwrite set to not step on the next tween. Is tweenlite doing something that causes the timeline to flake out? Just curious.

Still looking for an answer. Sigh.

RRH, I truly appreciate your assistance.

rrh
01-07-2009, 03:10 PM
I'm not telling you to create an array for the entire board, but an array of the moves that this piece is going to make in this turn.

I think the sticking point is you're expecting the .to() call to not complete until the entire tween is finished. The .to() call just *starts* the tween, so what you are doing is starting all the tweens at the same time.

invision-studios
01-07-2009, 05:16 PM
Doh!!

Thanks for pointing that out. I've never used tweenlite before, that's what I was trying to clarify. Makes sense now, to calculate the moves, stick them in an array, then pass them to the tweenlite.to.