Jump to content

Transitional Animation


BrunoHautenfaust
 Share

Recommended Posts

*Changed the thread title to something more accurate.

 

I have the following:

1/ Idle animation - ok

2/ press down and the animation changes to crouch - ok

 

What I want is to put an animation in between 1 and 2 which connects both animations, when I press down. And when I release the key, the 'going to crouch' animation should go in reversed order. Making it look like the character is getting up again.

===

What I've tried so far:

---1---if (downKey.isDown) {    if (downKey.onPress) {       player.animations.play('toCrouch');    }    player.animations.play('crouch');} ---2---if (downKey.isDown) {   downKey.onDown.addOnce(stopAnimation, this);    player.animations.play('crouch');} function stopAnimation() {    player.animations('toCrouch').stop(null, true);}

Another idea was to get the previous input or frame but I don't know how to do that in Phaser.

I also tried to make the animation not loop, but that didn't do anything. I'm in the update() method after all. How would I make something happen once when it's constantly looping?

I read about onUpCallback  but i didn't understand how to make things work. And I don't know whether the callback should be attached directly to the game.input.keyboard or Phaser.Keyboard prototype body. Do I need a callback at all here? Number 2 in the code snippet uses such but I think it's poorly written.

 

EDIT:

I looked at the "Keyboard Justpressed" tutorial again and decide to try this:

if (downKey.downDuration(100)) {       // Duration is important! If it's, say, 250, the animation might loop or something	player.animations.play('toCrouch');} 			 else if (downKey.isDown) {       player.animations.play('crouching');      		}

It worked. Very elegant, I must say.

 You got downDuration/upDuration. Amazing!

Link to comment
Share on other sites

I noticed that downDuration is not the answer. When I focus off the browser and focus in, the animation plays. Meaning, the character ducks.

Is this what you have in mind:

I don't think it's working. I probably did it wrong.

        if (downKey.isDown) {        	Crouch(ToCrouch(player, 'toCrouch'));        }        // CALLBACK:	function Crouch(callback) {		if (callback) {		    callback();		}		player.animations.play('crouching');	}	function ToCrouch(obj, anim) {		obj.animations.play(anim).complete();	}
Link to comment
Share on other sites

Hmm. I'm not an expert at animations but could you try something like : 

var downAnimation = player.animations.add("down");var crouchAnimation = player.animations.add("crouch");crouchAnimation.onAnimationComplete = crouchAnimation;crouchAnimation.play();

If this works, you just have to trigger the crouch animation when player presses down, at automatically, once the crouch animation is finished, the down animation should start. 

 

Be careful, it's very probably full of syntax errors / objects misuse, I'm writing this without testing.

Link to comment
Share on other sites

function update() {	        	game.physics.arcade.collide(player, platforms);        	var lastKey = game.input.keyboard.lastKey;       		player.body.velocity.x = 0;        	// CONTROLS        	if (leftKey.isDown) {	           // Left        		player.body.velocity.x = -600;        		player.scale.setTo(-0.6, 0.6);        		player.animations.play('run');        	}        	else if(lastKey === leftKey) {   	// Stop Left        		player.scale.setTo(-0.6, 0.6);        		player.animations.play('stop');        	}        	else if (rightKey.isDown) {		// Right        		player.body.velocity.x = 600;            	player.scale.setTo(0.6, 0.6);                         	player.animations.play('run');        	}        	else if (lastKey === rightKey) {	// Stop Right            	player.scale.setTo(0.6, 0.6);            	            	player.animations.play('stop');            	              	}        	else if (upKey.isDown && player.body.touching.down) {	// Jump        		player.body.velocity.y = -450;        	}          	else if(downKey.isDown){           // Crouch        		if (downAnimation.complete()){        			crouchAnimation.play();        		}        		downAnimation.play();        	}                    else {                   // Idle		      player.animations.play('idle');        	} 	        }

That's the whole update function. I don't have a stacktrace to provide, since I'm not getting any errors in the console.

If you're wondering, the stop parts represent a short animation when I release left or right. But the animation keeps looping until I press something else. Maybe because the whole function update() is a loop.

Link to comment
Share on other sites

I don't really see where you are using my code suggestions. And I didn't know of a "lastKey" parameter but it makes your whole code very confusing. Why don't you use key.isDown and key.isUp?

 

And what I meant was something like : 

else if(downKey.isDown){  // Crouch    crouchAnimation.play();}

Provided that you created it the right way.

Link to comment
Share on other sites

crouchAnimation.onAnimationComplete = crouchAnimation;   // Invalid statement as you probably knowcrouchAnimation.play();

Well, this really didn't make much sense. The way I understand this, we play one animation. And when it's finished, it(the same animation) equals itself. Then you play it again. But I figured you must've meant:

crouchAnimation.onAnimationComplete = downAnimation;   // Invalid statementdownhAnimation.play();

And we didn't specify:

down - means bending

crouch - means already bent, crouching, ducking, right?

===

I'm not using keyUp because by default the key would be up. And the animation will play without me pressing anything.

else if(downKey.isDown){  // Crouch    crouchAnimation.play();}

This would work. But the animation would go directly from 'idle' to 'crouch'. There's no 'bending'. And I have to squeeze it in between somehow.

 

 

 

P.S. I'm getting confused here.  :wacko:

Link to comment
Share on other sites

Yeah I'm really sorry for the typo, but you got it in the end, gg for that. Having said that, you should make it work by reversing the two animations (because my understanding was wrong) : 

var crouchAnimation = player.animations.add("crouch");var downAnimation = player.animations.add("down");downAnimation.onAnimationComplete = crouchAnimation;downAnimation.play();

And then : 

...else if(downKey.isDown){  // Crouch    downAnimation.play();}
Link to comment
Share on other sites

OK, the keywords 'down' and 'crouch' are confusing me. Here's a legend:

 

Transition - the transitional animation

Crouching - when we're crouching on the floor

 

Is this what you mean(because it doesn't work). When I press down, I see only the first frame of the 'Transition' sequence:

.... other moves...else if(downKey.isDown){        // When I press DOWN  if (Transition.complete()) {   // If transition animation is complete     Crouching.play();        // play the animation in which the player is crouching  }   else {                     // If not, then        Transition.play();      // play the transition animation    }}...

EDIT:

 

There's a property 'currentAnim' that can be attached to a sprite(the player).

else if (lastKey === downKey) {	            player.currentAnim = transition;       player.play(player.currentAnim);            	       if (player.currentAnim.isFinished) {          player.play('idle');       }   	}

Still not working. Looks wrong anyway. I'm out of ideas.

 

EDIT 2:

 

Well, falling back to where we started. With minor updates. This works fine. Just the way I want it. Only problem is the focus off and focus in the browser which triggers the left and right stopping animations. If I can turn that off somehow, it would be great.

lastKey = game.input.keyboard.lastKey;if (leftKey.isDown) {	// Left       player.play('run');}else if (lastKey === leftKey && leftKey.upDuration(100)) { // Stop Left       player.play('stop');}else if (rightKey.isDown) {		// Right       player.play('run');}else if (lastKey === rightKey && rightKey.upDuration(100)) { // Stop Right       player.play('stop');}else if (downKey.downDuration(100)) {	// To Crouch       player.play('toCrouch');}else if (downKey.isDown) {	// Crouching       player.play('crouching');}
Link to comment
Share on other sites

After looking at your suggestion with fresh eyes this morning I see things differently. :D You meant playing one animation then switching it in the "create method" then call it with the last modification in the "update method". I was so fixated on the update method I thought that no matter what, the whole logic should happen there. ^^; Oops! Well, that's what happens when I stare at a code whole day without a break.  :lol: A mistake I can't resist sometimes.

 

Thanks anyway!  :)

Link to comment
Share on other sites

  • 2 months later...

Ok, Skeptron. After some toying around with sprites and animations I think I understand things a tad better.

I got your idea. It's really simple and great:

 

 

var crouchAnimation = player.animations.add("crouch");

var downAnimation = player.animations.add("down");

downAnimation.onAnimationComplete = crouchAnimation;
downAnimation.play();

And then : 

...
else if(downKey.isDown){ // Crouch
downAnimation.play();
}

 

 

 

Although, It only works at some point. Here's what I got (different animation names, big deal):

function create() {    running = krn.animations.add('run', Phaser.Animation.generateFrameNames('K', 9, 14));    jump = krn.animations.add('jump ', Phaser.Animation.generateFrameNames('K', 1, 6));    inAir = krn.animations.add('inAir', Phaser.Animation.generateFrameNames('K', 7, 8));    c = game.input.keyboard.createCursorKeys();// Note! jump.onComplete is a Phaser.Signal object. Using it also works but gives the same results as described further below. I'm not familiar with signal objects, though.    if (jump.isFinished) {           jump  = inAir;    }}function update() {    if (c.up.isDown) {        jump.play();    // This works. BUT the animation plays ONLY after I release the button AND sometimes it doesn't reach the last frame. It's supposed to work while I'm holding the button.   } else {    running.play();    // This does NOT work. Why?}

I mean, if var A = something.animations.add(...);

and something.animations.add(...).play() doesn't work. Why would A.play() work sometimes!?  

Link to comment
Share on other sites

You are still not doing what I'm suggesting.

 

And it works the way you described because in the update loop you will restart the jump animation as long as the key is down. So you will only see the first frame of the animation. And once you release the key, it will let the animation play, unless you touch a key again (in which case it will interrupt current animation for another animation). That's why it doesn't always play until the end.

Link to comment
Share on other sites

You are still not doing what I'm suggesting.

... Damn! Then the only thing left is your first idea - the callback. And if it's not that, then you can call Obi-Wan and tell him to tell me that I'm lost.  -_-

 

 

And it works the way you described because in the update loop you will restart the jump animation as long as the key is down. 

 

That doesn't make sense to me. In the doc API it says: The "down" state of the key will remain true for as long as the keyboard thinks this key is held down. So whatever is happening inside inside an if(key is down) statement should loop(by default).

And something I should've mentioned 2 months ago. The best way for me to play an animation(one that 100% works) is to write this:

 player.animations.play(<animation string>, <Playback speed>,<loop>);

But this:

var <something> = player.animations.add(<animation string>, Phaser.Animation.generateFrameNames(...));<something>.play();

I prefer not to just because it works occasionally(at most). It's useful to check different properties and perform methods, but play() is not one of them.

 

jmp909, I'll look into the finite state machine.

Link to comment
Share on other sites

You are checking if the key is down in the update() loop, that is, 60 times (or so) per second. So if you press the key down (let's say forever, for the sake of simplicity), in each update() loop the 'if' condition will be true : because "c.up.isDown" is true. So each time, it will enter the 'if' condition and play the jump animation. So 60 times per second the code will play the jump animation. Basically, the animation will never play because it keeps restarting!

 

Animations, when called, do not wait for previous animation to complete : they start immediately! So you'll be stuck on the first frame of the jump animation!

 

If you release the key, then the condition is false, and you'll stop restarting the animation. So the one started in the previous update() loop will be able to complete, unless you press another key and start another animation (or press same key again).

Link to comment
Share on other sites

So that's what you had in mind.......  :mellow: Never would've guessed.

I'm gonna mark this question as answered since it is. 

 

And ask one last question, if I may:

 The update loop is called 60 times per second. If I just put an endless animation. It plays. There's no condition, so you may say it's sort of a while(true). And the "condition" is constantly met. 60 times per second. How come the animation loops endlessly and is not stuck on the first frame then?

 

P.S. Sorry if I got too much on your nerves and wasted too much of your time. At this point I'm too embarrassed to even say thanks. But thanks. A million!

Link to comment
Share on other sites

It's very fine, I shouldn't have get upset like that. Not knowing is fine and that's what this forum is for. My apologies.

 

Let's make the most of this experience and remember that a sandbox is worth a thousand words! So let's jump to a concrete example faster next time.

 

Speaking of which : I can't reproduce your behaviour. I made a sandbox which perfectly illustrates what I explained : http://phaser.io/sandbox/edit/LAHsBjFE

 

Every update() I run the leftAnimation, which we can't see playing because it is perma-restarted.

Link to comment
Share on other sites

 

It's very fine, I shouldn't have get upset like that. Not knowing is fine and that's what this forum is for. My apologies.

 

Let's make the most of this experience and remember that a sandbox is worth a thousand words! So let's jump to a concrete example faster next time.

 

You're absolutely right. :) Sometimes(actually always) an example is the best thing.

 

 

 

Speaking of which : I can't reproduce your behaviour. I made a sandbox which perfectly illustrates what I explained : http://phaser.io/sandbox/edit/LAHsBjFE

 

Every update() I run the leftAnimation, which we can't see playing because it is perma-restarted.

 

About that, check this: http://phaser.io/sandbox/edit/lSjorbvI

Link to comment
Share on other sites

That's very interesting! The only difference between your code and mine is that I do animation.play() whereas you do animationManager.playAnimation("myAnimation"). And I looked at the doc and it's very clear that the animationManager handles the "already playing animation" case : http://phaser.io/docs/2.4.4/Phaser.AnimationManager.html#play

 

play(name, frameRate, loop, killOnComplete) → {Phaser.Animation}Play an animation based on the given key. The animation should previously have been added via animations.add**If the requested animation is already playing this request will be ignored**. If you need to reset an already running animation do so directly on the Animation object itself.
So it might be better to use your solution, that is to use the animationManager, when playing an animation. 
 
Also please note that your animation was not set to loop=true but loop=false (even though it doesn't change anything about our issue).
Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...