javascriptphaser-frameworksprite-sheetphaserjs

Character atlas/spritesheet animation with user input not stopping on key up Phaser 3


I'm working on animating a character (using a texture atlas) with user input in Phaser 3 and I'm running into an issue with the animation not stopping when I release the respective arrow button. I've tried a few tactics, and some of them only partially work. The code below is what I use which works as intended in all respects, except the animation doesn't stop after I release the respective arrow key. Maybe I need logic with stopping animation once the key is lifted? Any suggestions? Thanks!

I've used this post as an example, but it prevents the character from moving diagonally: Sprite Sheet animation with arrow keys

update() {      

    this.hero.setVelocity(0,0);

    if (this.cursors.up.isDown) {
        this.hero.anims.play('walkUp', true); 
        this.hero.setVelocityY(-200);                     
    } 
    
    else if (this.cursors.down.isDown) {
        this.hero.anims.play('walkDown', true) 
        this.hero.setVelocityY(200);
    }         

    if (this.cursors.left.isDown) {    
        this.hero.anims.play('walkLeft', true)
        this.hero.setVelocityX(-200);
    } 

    else if (this.cursors.right.isDown) {
        this.hero.anims.play('walkRight', true)
        this.hero.setVelocityX(200);
    }                
}

Solution

  • There are many ways to solve this. Your solution is ofcourse vaild, but here two alternative, the would keep your code abit shorter an easier to read.

    Update: After re-reading your question, I see that for your specific useCase the Alternative 2 would be the needed solution. Just adding those 3 lines to your initial code, should do the trick.

    Alternative 1

    Since movement to the left and right override the up and down movement you could simply reorder the if/else blocks and chain them all as ob big if/else block and stop the animation in the final else. (Me from the future, your if's only override the animation)

    update() {      
    
        this.hero.setVelocity(0,0);
    
        if (this.cursors.left.isDown) {    
            this.hero.anims.play('walkLeft', true)
            this.hero.setVelocityX(-200);
        } 
        else if (this.cursors.right.isDown) {
            this.hero.anims.play('walkRight', true)
            this.hero.setVelocityX(200);
        } 
        else if (this.cursors.up.isDown) {
            this.hero.anims.play('walkUp', true); 
            this.hero.setVelocityY(-200);                     
        } 
        else if (this.cursors.down.isDown) {
            this.hero.anims.play('walkDown', true) 
            this.hero.setVelocityY(200);
        }
        else {
            this.hero.anims.stop();
        }   
    }
    

    Alternative 2

    Just check at the end of the update function, if the velocity -length is more or less equal to zero. (Since the object often don't really stop (because of gravity, gliding and some physics round stuff ) < 2 should be save/okay to use)

    update() {      
    
        // ...  your initial code 
        if (this.hero.body.velocity.length() < 2) {
            this.hero.anims.stop();
        }   
         
    }
    

    In personally like the first altertive, but depending on your usecase, if you need to handle up/down and left/right independently, the later should be fine also.

    Improved Alternative 2 but slightly longer, you could check for the key events instead of the velocity-length and it would be "cleaner".

    if (!this.cursors.up.isDown &&
        !this.cursors.down.isDown &&
        !this.cursors.left.isDown &&
        !this.cursors.right.isDown ){
            this.hero.anims.stop();
    }