How would I play different animations depending on a key pressed?

Hey everyone,

I’m currently working on some character movement. I want to switch to a different index of the spritesheet, one for an idle animation, one for a running animation, depending if I press a directional key (in this case, D as in WASD keys) .

I figured id make two anim configs, one for the idle animation and the other for the running animation. Id load them, and initiate the play and resume function depending on if something is pressed. I initiated the play method inside the player update() function.

I haven’t tried to make a player create() function, and realized that maybe it would work with the update function. Im having trouble trying to find a demonstration and example on triggering animations, depending on with a key is pressed.

I had attempted to try what I had below, but the animation would stop while im pressing the key down, and would only run after I release. Also the run animation seemed sped up. Is this because the key pressed needs to be in its own player create() function, and shouldnt be in the player update() function? Not sure.

Heres my code:

import Phaser from 'phaser'

export class Player extends Phaser.Physics.Arcade.Image {
    constructor(scene, x, y, key, frame) {
        super(scene, x, y, key, frame) 
        this.scene = scene;
        this.velocity = 160;

        // enable physics
        this.scene.physics.world.enable(this)

        //set immovable if another object collides with our player
        this.setImmovable(false)

        // scale our player
        this.setScale(2);

        // collide with world bounds
        this.setCollideWorldBounds(true);

        // add the player to our existing scene
        this.scene.add.existing(this)

    // add the sprite
    this.sprite = this.scene.add.sprite(0, 0, "adventurer").setScale(2)

    // create animation config
    var animIdle = {
      key: 'idle',
      frames: this.scene.anims.generateFrameNames('adventurer', { start: 0, end: 5}),
      frameRate: 9,
      yoyo: false,
      repeat: -1
    }

    let animRun = {
      key: 'run',
      frames: this.scene.anims.generateFrameNames('adventurer', { start: 8, end: 13}),
      framerate: 2,
      yoyo: true,
      repeat: -1
    }

    // add config to animation variable
   this.scene.anims.create(animRun)
   this.scene.anims.create(animIdle)

    // load run animation?
    this.sprite.anims.load('idle');

    // play idle animation till specified otherwise
    this.sprite.anims.play('idle');

    // load run animation?
    this.sprite.anims.load('run');
    }

    update(cursors) {
        this.body.setVelocity(0);

   // sprite will follow player vector
        this.sprite.x = this.x
        this.sprite.y = this.y

        if(cursors.A.isDown) {
          this.body.setVelocityX(-this.velocity);
        // trigger run animation
        this.sprite.anims.play('run');
        } else if (cursors.D.isDown) {
          this.body.setVelocityX(this.velocity);
        } 
        if(cursors.W.isDown) {
          this.body.setVelocityY(-this.velocity);
        } else if (cursors.S.isDown) {
          this.body.setVelocityY(this.velocity);
        }
    }
}

I would do more research but its late and will have to wait till tommorow.
If anyone could lead me in the right direction, I’d really appreciate it.

Thanks.

this.sprite.anims.play('run', true); You need to passing that boolean parameter to make sure it not stuck while the anims playing.

1 Like

So I added a new key press using isUp, so when key D is up the idle animation will play. This works. Except the run animation is playing at a high framerate, even when I have set the config framerate to 2.

let animRun = {
      key: 'run',
      frames: this.scene.anims.generateFrameNames('adventurer', { start: 8, end: 13}),
      framerate: 2,
      yoyo: false,
      repeat: -1
    }

Im not sure why this would be the case. If I set the boolean to true with the play function, that animation will run correctly, just with the wrong framerate.

update(cursors) {
        this.body.setVelocity(0);

        this.sprite.x = this.x
        this.sprite.y = this.y

        if(cursors.A.isDown) {
          this.body.setVelocityX(-this.velocity);
        } else if (cursors.D.isDown) {
          this.body.setVelocityX(this.velocity);
          this.sprite.anims.play('run', true)
        } 

        if(cursors.W.isDown) {
          this.body.setVelocityY(-this.velocity);
        } else if (cursors.S.isDown) {
          this.body.setVelocityY(this.velocity);
        }
        if(cursors.D.isUp) {
          this.sprite.anims.play('idle', true);
        }
    }

I’m using the anims.load function in the constructor of the player.

try with frameRate, with big R
Maybe it not passing properly

1 Like

So now I’m trying to trigger an attack animation using the Z key while having a run animation which can be triggered by the D key (via WASD).

if (cursors.D.isDown) {
   this.sprite.anims.play('run', true)
} else if (cursors.D.isUp) {
   this.sprite.anims.play('idle', true)
}

if (Phaser.Input.Keyboard.JustDown(keyZ)) {
     if (this.playerAttacking == false) {
        this.playerAttacking = true
        this.sprite.anims.play('swordhit', true);
        this.sprite.anims.remove('idle');

        this.timer = this.scene.time.delayedCall(300, () => {
           this.playerAttacking = false;
           this.sprite.anims.stop('swordhit', false)
           this.sprite.anims.play('idle', false);
         }, [], this)
  }

It seems that the cursors.D.isUp which triggers the idle animation as I let go of the D key, is interferring with the attack animation. If I remove the D.isUp code, and initialize the idle animation in the constructor, the attack animation will work fine. After the attack animation has finished, it will reset back to the idle animation already playing from the constructor, or at least thats what I assume is happening.

Perhaps there is a more logical way to implement this, a more standard way of approaching this. If anyone could help me, I’d really appreciate it.

I’ll post all my code once I’ve achieved this so others can check it out. Thanks.

This problem comes with your code structure, maybe you need reassure that the flow and order of animation correctly. This commonly achieve by state management for animation, to make sure no inferring other animation state while the other is playing (in your case, between move and attack).
Or try with switch…case conditional, rather that else…if?