Sign in to follow this  
Jekyll

Animation on keypress

Recommended Posts

Hi, I've been using Phaser for about a month now and I'm really enjoying it so far. I've just recently came up with a problem that I'm not able to find a solution to with any of my searches.
 

I have a basic player character that moves and plays a run animation when I press left or right on the arrow keys. The animations play perfectly and loop like they are supposed to. However I am trying to add an attacking animation, that plays when the player presses the space bar for example, but it doesn't play through the entire animation like my run animation does. It is stuck on the first frame for as long as I hold the attack key. Furthermore if I change the movement code that moves the player right when the right arrow key is pressed to instead play the attack animation instead of the run animation it plays through correctly. Are the left and right cursor input keys treated differently than other keys whereas the left and right arrow keys are continuously 'fired' off and other keys send just one signal?

In my player's preload function I create my sprite and add a few animations to it. I have the attack animation set to not loop. I thought this may have had something to do with my problem, but changing it to loop does nothing.

this.sprite = this.game.add.sprite(64, 64, 'playerSprites');this.sprite.animations.add('idle', [0, 1, 2, 3], 4, true);this.sprite.animations.add('run', [8, 9, 10, 11], 8, true);this.sprite.animations.add('attack', [16, 17], 4, false);

In my players create function I set up the cursor keys and the spacebar.

this.dpad = this.game.input.keyboard.createCursorKeys();this.attackButton = this.game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

In the players update function I check my input and change animations accordingly.

if (this.dpad.left.isDown) {    this.sprite.body.velocity.x = -this.maxVelocityX;    this.sprite.animations.play('run');    this.facing = 'left';}elseif (this.dpad.right.isDown) {    this.sprite.body.velocity.x = this.maxVelocityX;    this.sprite.animations.play('run'); //If I change this to play the 'attack' animation it loops correctly    this.facing = 'right';}else{    this.sprite.animations.play('idle');}if(this.attackButton.isDown){    this.sprite.animations.play('attack'); //When I press the spacebar it only displays the first                                                                         //frame of the attack animation no matter how long I hold the key.}

If anyone has any insight on what is going on here I would greatly appreciate the help. =)

Share this post


Link to post
Share on other sites

There is a conflict in the 'else' portion of the code. Currently, if you stand still and attack, the game is gonna be doing the following:

- Character has not moved so animation is idle

- Character attacked so animation is attack

 

And it will overwrite the animation that should be played over and over again.

 

This *should* fix it:

if(this.attackButton.isDown){       this.sprite.animations.play('attack'); } else if (this.dpad.left.isDown) {    this.sprite.body.velocity.x = -this.maxVelocityX;    this.sprite.animations.play('run');    this.facing = 'left';} else  if (this.dpad.right.isDown) {    this.sprite.body.velocity.x = this.maxVelocityX;    this.sprite.animations.play('run');    this.facing = 'right';} else {    this.sprite.animations.play('idle');}

I hope this helps :)

 

You might want to change from isDown to justPressed for the attack animation though. http://docs.phaser.io/Phaser.Keyboard.html#justPressed

Share this post


Link to post
Share on other sites

Yeah, that nearly fixes it though it only displays the attack animation for a split second and then returns to the idle animation. I have fixed this by giving the player a canAttack flag and an attackTimer that determines when the player can attack again but this feels hack-y.

var canAttack = true;var attackTimer = 0;if(this.attackButton.isPressed()){    if(canAttack){        this.sprite.animations.play('attack');        canAttack = false;        attackTimer = this.game.time.now + 300;    } } else if (this.dpad.left.isDown) {    this.sprite.body.velocity.x = -this.maxVelocityX;    if(canAttack){ //allows attacking while moving        this.sprite.animations.play('run');    }    this.facing = 'left';} else  if (this.dpad.right.isDown) {    this.sprite.body.velocity.x = this.maxVelocityX;    if(canAttack){        this.sprite.animations.play('run');    }    this.facing = 'right';} else {    if(canAttack && this.game.time.now > attackTimer){        this.sprite.animations.play('idle');    }}

I've tried placing a check in the update for when the sprite.animations.isFinished it set's the canAttack flag back to true, but for some reason this does not work nor does storing the attack animation and then checking whether it isFinished. In both cases isFinished is undefined?

if(this.sprite.animations.isFinished){    //play idle animation}console.log(this.sprite.animations.isFinished); //'undefined'//attack(){    var attackAnim = this.sprite.animations.play('attack');//}//update(){    if(attackAnim.isFinished){        //play idle animation    }    console.log(attackAnim.isFinished); //'undefined'//}

And I've tried accessing the currentAnim and checking whether it isFinished but it doesn't work either.

Share this post


Link to post
Share on other sites

It might seem hacky but it is a normal thing - you need to set things like how often a person can attack and whatnot. I would have used a Phaser timer though, would help it look a bit cleaner. This way you also don't need to add anything to the update function (so, cleaner code overall).

    var canAttack = true;         if(this.attackButton.isPressed()){      if(canAttack){        this.sprite.animations.play('attack');        canAttack = false;        game.time.events.add(300, (function() {             canAttack = true;        }), this);      }    } //and then all the other elses and ifs

Your ifs are a bit iffy though - they are not gonna behave as you want. The second if is never getting checked if you have pressed the attack button, you need to change it.

    var canAttack = true;         if(this.attackButton.isPressed() && this.dpad.left.isDown){      if(canAttack){        this.sprite.animations.play('attack_left');        canAttack = false;        game.time.events.add(300, (function() {           canAttack = true;        }), this);      }    } //And you would probably have to do this for other combinations

Share this post


Link to post
Share on other sites

I don’t know if anyone else has noticed this, but in the original code the attack animation had false as the last parameter of the animation. Based on my experiences with this problem, if you change that false to true, it should play the whole animation.

this.sprite = this.game.add.sprite(64, 64, 'playerSprites');this.sprite.animations.add('idle', [0, 1, 2, 3], 4, true);this.sprite.animations.add('run', [8, 9, 10, 11], 8, true);this.sprite.animations.add('attack', [16, 17], 4, false);

                                 ⬆️⬆️⬆️

Edited by Dguto9

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.