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

Unity中如何等待动画播放完成?协程方案失效求其他解决方法

问题原因分析

你原方案失效的核心原因有三点:

  • 调用anim.SetBool后Animator不会立刻切换到目标动画状态,你立刻获取的GetCurrentAnimatorStateInfo还是切换前的状态数据,拿到的时长自然是错误的
  • 等待时间计算逻辑错误:normalizedTime是当前状态已播放的比例(值为1代表播放完一遍),直接和状态长度相加的逻辑完全不符合预期
  • 额外调用逻辑问题:你在BlockPlayer方法中同时启动三个动画协程,三个协程会并行执行,动画会互相覆盖,根本不会按顺序播放
可行实现方案

方案1:修正协程逻辑(无需修改动画资源,最便捷)

直接监听动画状态的播放进度,不要用固定时长等待,修正后的PlayAnim协程代码如下:

IEnumerator PlayAnim(Animator anim, string boolParamName, string targetStateName)
{
    anim.SetBool(boolParamName, true);
    // 先等待Animator进入目标动画状态
    yield return new WaitUntil(() => anim.GetCurrentAnimatorStateInfo(0).IsName(targetStateName));
    // 再等待当前状态播放完成(normalizedTime >=1 即播放完一遍)
    yield return new WaitUntil(() => anim.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f);
    anim.SetBool(boolParamName, false);
}

调用时需要传入对应的状态名,比如播放Attack动画就写:

StartCoroutine(PlayAnim(anim, "Attack", "Attack"));

如果需要按顺序播放多个动画,需要把调用方法也改成协程,逐个等待:

public IEnumerator BlockPlayer(GameObject playerPos, Animator anim, NavMeshAgent agent, float inRange, float inView, GameObject self)
{        
    yield return StartCoroutine(PlayAnim(anim, "Block", "Block"));                
    yield return StartCoroutine(PlayAnim(anim, "BlockAttack", "BlockAttack"));            
    yield return StartCoroutine(PlayAnim(anim, "Attack", "Attack"));
    state = State.Attack;
}
// 调用BlockPlayer的地方用StartCoroutine启动即可

方案2:使用Animation Event(精度最高,适合需要和动画帧严格对齐的场景)

操作步骤:

  1. 打开Unity的Animation窗口,选中你要监听的动画剪辑
  2. 把时间轴拖到动画的最后一帧,点击窗口上的「Add Event」按钮
  3. 在事件的Inspector面板中,填写要触发的方法名(比如OnAttackAnimEnd)
  4. 在挂载Animator的GameObject对应的脚本里添加对应方法:
// 攻击动画结束时会自动触发该方法
public void OnAttackAnimEnd()
{
    anim.SetBool("Attack", false);
    // 这里直接写动画结束后要执行的逻辑即可
}

如果需要区分不同动画的结束事件,给每个动画的最后一帧添加不同的事件方法即可。

方案3:使用Animator State Machine Behaviour

如果你不想在每个业务脚本里写监听逻辑,可以给Animator的对应状态添加StateMachineBehaviour:

  1. 选中Animator窗口里的目标动画状态,在Inspector面板点击「Add Behaviour」,新建一个继承自StateMachineBehaviour的脚本
  2. 重写OnStateExit方法,在状态退出时执行逻辑:
public class AttackStateBehaviour : StateMachineBehaviour
{
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.SetBool("Attack", false);
        // 执行动画结束后的逻辑
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:15:06