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

Unity 2D俯视角学生游戏攻击动画仅1帧即切回Idle问题求助

解决Unity 2D俯视角游戏攻击动画仅播放1帧的问题

嘿,我来帮你搞定这个攻击动画的问题!你的代码逻辑里有个关键小漏洞,导致攻击动画刚播放一帧就被切回Idle了,我来给你拆解清楚,再给你修复方案。

问题根源

你的Update()方法每帧都会执行一次完整的判断逻辑:

  • 当你按下Fire1的那一瞬间,代码进入攻击分支,播放Attack动画;
  • 但到了下一帧,CrossPlatformInputManager.GetButtonDown("Fire1")就不成立了(因为GetButtonDown只在按下的第一帧返回true),代码直接跳到else分支,把动画切回Idle,这就导致Attack动画只播了一帧就被打断。

修复方案

核心思路是:用一个状态变量标记当前是否正在攻击,在攻击动画播放的全过程中,跳过移动和Idle的状态判断,直到攻击动画完全播放完毕。

步骤1:添加攻击状态标记

在你的脚本类里添加一个私有布尔变量,用来记录当前是否处于攻击状态:

private bool isAttacking = false;

步骤2:调整Update方法的逻辑优先级

把攻击相关的判断放在最前面,并且在攻击状态生效时跳过其他逻辑:

void Update () {
    // 如果正在攻击,直接跳过后续所有逻辑,避免打断动画
    if (isAttacking) {
        return;
    }

    Move();
    float lastInputX = CrossPlatformInputManager.GetAxis("Horizontal");
    float lastInputY = CrossPlatformInputManager.GetAxis("Vertical");

    // 优先处理攻击输入:只有不在攻击状态时才能触发新的攻击
    if (CrossPlatformInputManager.GetButtonDown("Fire1")) {
        isAttacking = true;
        anim.SetBool("Attacking", true);
        anim.Play("Attack");
        return; // 触发攻击后,直接结束当前帧的逻辑,不处理移动/Idle
    }

    // 处理移动/Idle逻辑
    if (lastInputX != 0 || lastInputY != 0) {
        anim.SetBool("Walking", true);
        anim.SetFloat("LastMoveX", lastInputX);
        anim.SetFloat("LastMoveY", lastInputY);
        anim.Play("Walk");
    } else {
        anim.SetBool("Walking", false);
        anim.Play("Idle");
    }

    float inputX = CrossPlatformInputManager.GetAxis("Horizontal");
    float inputY = CrossPlatformInputManager.GetAxis("Vertical");
    anim.SetFloat("SpeedX", inputX);
    anim.SetFloat("SpeedY", inputY);
}

步骤3:动画结束后重置攻击状态

这里推荐用Unity动画事件来同步动画结束的时机,比用协程等待时长更可靠:

  1. 在脚本里添加一个公开的回调方法:
// 这个方法会在攻击动画播放完毕时被调用
public void OnAttackAnimationFinished() {
    isAttacking = false;
    anim.SetBool("Attacking", false);
}
  1. 打开Unity的Animation窗口,选中你的Attack动画,在动画的最后一帧右键选择「Add Event」;
  2. 在Inspector面板的动画事件设置里,把这个OnAttackAnimationFinished方法拖到函数选择框里,这样动画播放到最后一帧时就会自动调用这个方法,重置攻击状态。

备选方案:用协程等待动画时长

如果你不想用动画事件,也可以用协程来实现,不过要注意动画时长要和实际播放时长匹配:

IEnumerator AttackCoroutine() {
    isAttacking = true;
    anim.SetBool("Attacking", true);
    anim.Play("Attack");
    
    // 获取当前Attack动画的时长,等待播放完毕
    yield return new WaitForSeconds(anim.GetCurrentAnimatorStateInfo(0).length);
    
    isAttacking = false;
    anim.SetBool("Attacking", false);
}

然后在触发攻击的地方替换成:

if (CrossPlatformInputManager.GetButtonDown("Fire1")) {
    StartCoroutine(AttackCoroutine());
    return;
}

额外提示

  • 记得在Animator Controller里,确保Attack状态和Idle/Walk状态的过渡条件设置正确,避免动画被意外打断;
  • 测试的时候可以打开Animator窗口的Debug模式,实时查看当前的动画状态,方便排查问题。

内容的提问来源于stack exchange,提问作者TobiasNorum

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 12:48:09