BrunoHautenfaust Posted August 27, 2015 Share Posted August 27, 2015 *Changed the thread title to something more accurate. I have the following:1/ Idle animation - ok2/ 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 More sharing options...
Skeptron Posted August 27, 2015 Share Posted August 27, 2015 Even more sexy would be to put the "down animation" into a callback method of the "crouch animation". Once the crouch animation is complete, it would call the down animation. Thus you could change the length of your animation and your code would still work perfectly. Doc : http://phaser.io/docs/2.4.3/Phaser.Animation.html#complete drhayes 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 27, 2015 Author Share Posted August 27, 2015 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 More sharing options...
Skeptron Posted August 27, 2015 Share Posted August 27, 2015 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 More sharing options...
BrunoHautenfaust Posted August 27, 2015 Author Share Posted August 27, 2015 Loosely following your code, here's what I did: if (downKey.isDown){ if (downAnimation.complete()){ crouchAnimation.play(); } downAnimation.play();}However, this doesn't go to the crouchAnimation. Link to comment Share on other sites More sharing options...
Skeptron Posted August 27, 2015 Share Posted August 27, 2015 Could you print a bit more code? And a stacktrace? Please keep in mind that we do not have your game right behind our eyes. Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 27, 2015 Author Share Posted August 27, 2015 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 More sharing options...
Skeptron Posted August 27, 2015 Share Posted August 27, 2015 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 More sharing options...
BrunoHautenfaust Posted August 27, 2015 Author Share Posted August 27, 2015 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 bendingcrouch - 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. Link to comment Share on other sites More sharing options...
Skeptron Posted August 27, 2015 Share Posted August 27, 2015 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();} BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 27, 2015 Author Share Posted August 27, 2015 OK, the keywords 'down' and 'crouch' are confusing me. Here's a legend: Transition - the transitional animationCrouching - 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 More sharing options...
Skeptron Posted August 28, 2015 Share Posted August 28, 2015 Sorry man but I'll stop helping you, because you don't listen to what I say. I write the exact code to use and you still somehow manage to do something else. No wonder why it doesn't work. Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 28, 2015 Author Share Posted August 28, 2015 After looking at your suggestion with fresh eyes this morning I see things differently. 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. A mistake I can't resist sometimes. Thanks anyway! Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted November 9, 2015 Author Share Posted November 9, 2015 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){ // CrouchdownAnimation.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 More sharing options...
jmp909 Posted November 9, 2015 Share Posted November 9, 2015 You could also consider a Finite State Machine http://www.adam-holden.com/blog/2014/05/more-amd-modularization-and-finite-state-machines-in-phaser/I'll try dig out the example with the dog sleep->lie->sit->walk->run example Link to comment Share on other sites More sharing options...
Skeptron Posted November 10, 2015 Share Posted November 10, 2015 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 More sharing options...
BrunoHautenfaust Posted November 10, 2015 Author Share Posted November 10, 2015 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 More sharing options...
Skeptron Posted November 10, 2015 Share Posted November 10, 2015 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). BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
Skeptron Posted November 10, 2015 Share Posted November 10, 2015 Ok so I was tired of this endless debate so I made a Phaser Sandbox for you : http://phaser.io/sandbox/edit/gJDAGqFA Press spaceBar to start the leftAnimation, which will automatically continue with the rightAnimation as soon as it completes. Of course, if you spam the spaceBar it will restart the leftAnimation. Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted November 10, 2015 Author Share Posted November 10, 2015 So that's what you had in mind....... 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 More sharing options...
Skeptron Posted November 10, 2015 Share Posted November 10, 2015 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 More sharing options...
BrunoHautenfaust Posted November 10, 2015 Author Share Posted November 10, 2015 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 More sharing options...
jmp909 Posted November 10, 2015 Share Posted November 10, 2015 this is the finite state machine demo i was referring to (hold right cursor down)https://github.com/aroth/phaser-extend-sprite-statemachine-example from herehttp://www.html5gamedevs.com/topic/17541-interactive-sprite-state-machine-example-w-demo BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted November 11, 2015 Author Share Posted November 11, 2015 Nice! Thanks, jmp909. This could really come in handy. Link to comment Share on other sites More sharing options...
Skeptron Posted November 11, 2015 Share Posted November 11, 2015 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 More sharing options...
Recommended Posts