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(精度最高,适合需要和动画帧严格对齐的场景)
操作步骤:
- 打开Unity的Animation窗口,选中你要监听的动画剪辑
- 把时间轴拖到动画的最后一帧,点击窗口上的「Add Event」按钮
- 在事件的Inspector面板中,填写要触发的方法名(比如
OnAttackAnimEnd) - 在挂载Animator的GameObject对应的脚本里添加对应方法:
// 攻击动画结束时会自动触发该方法 public void OnAttackAnimEnd() { anim.SetBool("Attack", false); // 这里直接写动画结束后要执行的逻辑即可 }
如果需要区分不同动画的结束事件,给每个动画的最后一帧添加不同的事件方法即可。
方案3:使用Animator State Machine Behaviour
如果你不想在每个业务脚本里写监听逻辑,可以给Animator的对应状态添加StateMachineBehaviour:
- 选中Animator窗口里的目标动画状态,在Inspector面板点击「Add Behaviour」,新建一个继承自
StateMachineBehaviour的脚本 - 重写
OnStateExit方法,在状态退出时执行逻辑:
public class AttackStateBehaviour : StateMachineBehaviour { override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { animator.SetBool("Attack", false); // 执行动画结束后的逻辑 } }
内容的提问来源于stack exchange,提问作者Arnice123
相关产品推荐
相关产品推荐

