Phaser 3攻击动画按X键卡首帧及按键状态处理问题求助
问题解决:Phaser 3 攻击动画卡顿与单次攻击触发实现
问题原因分析
你的代码存在两个核心问题:
- 动画执行顺序冲突:每帧
update中先判断速度为0时播放静止动画,之后才处理攻击动画。即使按下X键触发攻击,下一帧的静止动画逻辑又会覆盖攻击动画,导致攻击动画永远停在第一帧。 - 按键触发逻辑问题:使用
isDown会在按住X键时持续触发攻击逻辑,无法实现“播放完一次攻击后即使按住也不重复触发”的需求。
修改后的完整代码
import Phaser from "phaser"; import Enemies from "../components/Enemies"; import Hitbox from "../components/Hitbox"; export default class Player extends Phaser.GameObjects.Sprite { constructor(scene, x, y, texture, velocity) { super(scene, x, y, texture); this.setTexture("C4"); scene.add.existing(this); scene.physics.add.existing(this); this.scene = scene; this.body.allowGravity = false; this.velocity = velocity; this.cursor = scene.input.keyboard.createCursorKeys(); this.xKey = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.X); this.KeySave = null; this.facingDirection = null; this.damageAmount = 100; // 添加攻击状态标记 this.isAttacking = false; // 监听攻击动画完成事件 this.on('animationcomplete', (anim) => { if (anim.key.startsWith('Attack')) { this.isAttacking = false; // 重置X键状态,按住时视为已抬起 this.xKey.reset(); } }); } update() { // 攻击期间跳过其他逻辑 if (this.isAttacking) { return; } this.body.setVelocity(0); let isMoving = false; if (this.cursor.left.isDown) { this.body.setVelocityX(-this.velocity); this.anims.play("walkingLeft", true); this.KeySave = "left"; isMoving = true; } else if (this.cursor.right.isDown) { this.body.setVelocityX(this.velocity); this.anims.play("walkingRight", true); this.KeySave = "right"; isMoving = true; } else if (this.cursor.up.isDown) { this.body.setVelocityY(-this.velocity); this.anims.play("walkingUp", true); this.KeySave = "up"; isMoving = true; } else if (this.cursor.down.isDown) { this.body.setVelocityY(this.velocity); this.anims.play("walkingDown", true); this.KeySave = "down"; isMoving = true; } if (this.KeySave !== null) { this.facingDirection = this.KeySave; } // 根据是否移动判断播放静止动画 if (!isMoving) { switch (this.facingDirection) { case "left": this.anims.play("leftStop", true); break; case "right": this.anims.play("rightStop", true); break; case "up": this.anims.play("upStop", true); break; case "down": this.anims.play("downStop", true); break; default: this.anims.play("downStop", true); } } // 使用JustDown确保单次触发攻击 if (Phaser.Input.Keyboard.JustDown(this.xKey)) { this.isAttacking = true; this.body.setVelocity(0); let attackAnim = ""; switch (this.facingDirection) { case "left": attackAnim = "AttackLeft"; break; case "right": attackAnim = "AttackRight"; break; case "up": attackAnim = "AttackUp"; break; case "down": attackAnim = "AttackDown"; break; default: attackAnim = "AttackDown"; } this.anims.play(attackAnim, true); } } }
关键修改点说明
- 攻击状态锁
isAttacking:攻击动画播放期间,跳过移动和静止动画逻辑,彻底避免动画冲突。 JustDown替代isDown:仅在X键首次按下时触发攻击,按住时不会重复触发。- 动画完成事件监听:攻击动画播放完毕后,重置攻击状态,并调用
xKey.reset()重置按键状态,实现“按住X键也视为已抬起”的效果,必须松开后再次按下才能触发下一次攻击。 isMoving标志优化静止动画逻辑:用是否按下方向键判断是否播放静止动画,比速度判断更直接可靠。- 强制播放动画:所有
anims.play添加true参数,确保动画能强制切换,避免因当前动画相同而不播放的问题。
内容的提问来源于stack exchange,提问作者SebaPasto
相关产品推荐
相关产品推荐

