Jekyll Posted October 23, 2014 Share Posted October 23, 2014 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. =) Link to comment Share on other sites More sharing options...
OttoRobba Posted October 23, 2014 Share Posted October 23, 2014 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 Link to comment Share on other sites More sharing options...
Jekyll Posted October 24, 2014 Author Share Posted October 24, 2014 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. Link to comment Share on other sites More sharing options...
OttoRobba Posted October 24, 2014 Share Posted October 24, 2014 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 ifsYour 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 Link to comment Share on other sites More sharing options...
Dguto9 Posted December 12, 2019 Share Posted December 12, 2019 (edited) 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 December 12, 2019 by Dguto9 Link to comment Share on other sites More sharing options...
Recommended Posts