You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Phaser 3攻击动画按X键卡首帧及按键状态处理问题求助

问题解决:Phaser 3 攻击动画卡顿与单次攻击触发实现

问题原因分析

你的代码存在两个核心问题:

  1. 动画执行顺序冲突:每帧update中先判断速度为0时播放静止动画,之后才处理攻击动画。即使按下X键触发攻击,下一帧的静止动画逻辑又会覆盖攻击动画,导致攻击动画永远停在第一帧。
  2. 按键触发逻辑问题:使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:56:04