Unity中如何在动画播放完成后执行后续代码?
动画状态判断失效的核心原因
- 之前用的两个判断方法本身存在硬伤,且使用方式逻辑错误:
- 触发Animator参数后,动画不会立刻切换到目标状态,中间存在过渡(Transition)窗口期,这期间
GetCurrentAnimatorStateInfo(0)拿到的还是上一个状态的信息,计算出来的normalizedTime和目标动画完全无关,自然判断不准。 normalizedTime的数值逻辑不适合直接拿来判断结束:非循环动画播完后数值会持续累加超过1,循环动画播完后数值会重置为0,两种场景下用<1或者和length对比的写法都会出错。- 把判断逻辑放在单次执行的
if语句里完全没用——动画播放是跨越多帧的过程,单次判断只会读取执行当下那一帧的状态,不会持续追踪播放进度,必然出现提前执行或者完全不执行的问题。
- 触发Animator参数后,动画不会立刻切换到目标状态,中间存在过渡(Transition)窗口期,这期间
- 之前写的
WaitForSecondsRealtime固定等待协程,不是不能跨类调用,是协程启动逻辑写死在方法内部了,外部类只要拿到脚本引用,一样可以启动协程,只是硬编码等待时间的适配性太差,动画时长改了就要同步改等待时间,很容易出bug。
推荐实现方案
优先选动画事件+公开协程的方案,精度最高,维护成本最低,完全支持跨类调用:
- 第一步:打开缩小消失动画剪辑,在时间轴最后一帧的位置添加动画事件,事件绑定到对应UI脚本的无参方法,动画播到最后一帧会自动调用这个方法。
- 第二步:在UI脚本里写公开的触发方法,内部用标记位+协程等待动画真正播放完成后再执行移出逻辑,示例代码如下:
using UnityEngine; using System.Collections; public class HideableUI : MonoBehaviour { private Animator _animator; private bool _hideAnimFinished = false; // 供外部类调用的公开入口,直接调用即可,不需要外部处理协程 public void TriggerHideAndMoveOut() { _hideAnimFinished = false; // 替换成自己Animator里配置的触发参数名 _animator.SetTrigger("PlayHideAnim"); StartCoroutine(DoMoveAfterAnim()); } // 给动画事件绑定的方法,访问级别设为私有即可 private void OnHideAnimationComplete() { _hideAnimFinished = true; } private IEnumerator DoMoveAfterAnim() { // 等到动画事件触发标记位为真,再执行后续逻辑 yield return new WaitUntil(() => _hideAnimFinished); // 替换成自己的移出画布逻辑 transform.localPosition = new Vector3(9999, 9999, 0); } private void Awake() { _animator = GetComponent<Animator>(); } }
跨类调用时,只要拿到目标UI对象上的HideableUI组件引用,直接调用TriggerHideAndMoveOut()即可,不需要额外处理其他逻辑。
如果不想修改动画剪辑加动画事件,可以用纯代码轮询状态的协程方案,精度比硬等固定时长高很多,示例代码:
private IEnumerator DoMoveAfterAnim() { _animator.SetTrigger("PlayHideAnim"); int targetStateHash = Animator.StringToHash("缩小动画的状态名"); AnimatorStateInfo currentState; // 先等待Animator切换到目标动画状态 do { currentState = _animator.GetCurrentAnimatorStateInfo(0); yield return null; } while (currentState.shortNameHash != targetStateHash || currentState.normalizedTime < 0f); // 再等待目标状态播放完成 do { currentState = _animator.GetCurrentAnimatorStateInfo(0); yield return null; } while (currentState.shortNameHash == targetStateHash && currentState.normalizedTime < 1f); // 执行移出逻辑 transform.localPosition = new Vector3(9999, 9999, 0); }
用这个方案要注意把Animator里目标状态的退出过渡时间设为0,避免动画播完后自动切回其他状态影响判断。
内容的提问来源于stack exchange,提问作者The Crazy
相关产品推荐
相关产品推荐

