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

Unity中如何在动画播放完成后执行后续代码?

动画状态判断失效的核心原因
  • 之前用的两个判断方法本身存在硬伤,且使用方式逻辑错误:
    1. 触发Animator参数后,动画不会立刻切换到目标状态,中间存在过渡(Transition)窗口期,这期间GetCurrentAnimatorStateInfo(0)拿到的还是上一个状态的信息,计算出来的normalizedTime和目标动画完全无关,自然判断不准。
    2. normalizedTime的数值逻辑不适合直接拿来判断结束:非循环动画播完后数值会持续累加超过1,循环动画播完后数值会重置为0,两种场景下用<1或者和length对比的写法都会出错。
    3. 把判断逻辑放在单次执行的if语句里完全没用——动画播放是跨越多帧的过程,单次判断只会读取执行当下那一帧的状态,不会持续追踪播放进度,必然出现提前执行或者完全不执行的问题。
  • 之前写的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 05:45:41