Unity Animator 挥棒动画播放结束后卡住,无法正常返回idle状态
挥击动画卡末尾帧问题的成因与修复
核心问题定位
- 脚本触发逻辑时序错位:当前代码逻辑为鼠标按下时将 Animator 的
attacking参数设为true,鼠标抬起时才将该参数设为false。如果 swing 到 idle 的过渡条件绑定了attacking == false,就会出现动画播完末尾帧后,只要鼠标没有抬起,回切 idle 的过渡就永远不触发的问题,表现为必须抬起鼠标、甚至多次点击才能切回 idle 状态。 - 状态机配置常见疏漏:如果 swing 状态误开启了 Loop Time 循环属性、或 swing → idle 的过渡没有设置正确的触发时机,都会导致动画播完后卡在末尾帧无响应。
- 代码逻辑冗余:脚本中定义的私有布尔变量
attacking全程没有参与逻辑判断,连续快速点击鼠标时会导致 Animator 的参数状态被反复覆盖,时序混乱加剧卡帧问题。
可直接落地的修复步骤
- 调整脚本的动画触发逻辑,不再依赖鼠标抬起动作触发回切
替换原来的 FixedUpdate 触发逻辑,让 swing 动画播放完成后自动复位动画参数,不需要等鼠标抬起:
private Animator anim; private bool attacking = false; public Camera cam; public float swingDuration = 0.8f; // 和swing动画实际时长保持一致 public float dmg; public float range; void Start() { anim = GetComponent<Animator>(); } void Update() { // 仅在未处于攻击状态时响应挥击输入 if (Input.GetButtonDown("Fire1") && !attacking) { attacking = true; StartCoroutine(ExecuteSwing()); } } IEnumerator ExecuteSwing() { // 原有近战射线判定逻辑保留在这里 if (Physics.Raycast(cam.transform.position, cam.transform.forward, out RaycastHit hit, range)) { enemyHealth enemy = hit.transform.GetComponent<enemyHealth>(); if (enemy != null) { enemy.TakeDmg(dmg); } } // 触发挥击动画 anim.SetBool("attacking", true); // 等待挥击动画完全播放完成 yield return new WaitForSeconds(swingDuration); // 自动复位参数,触发回切idle anim.SetBool("attacking", false); attacking = false; }
- 修正 Animator 控制器的配置
- 选中 swing 动画状态,取消勾选 Loop Time 属性,避免挥击动画无限循环
- 检查 swing → idle 的过渡连线:确认过渡触发条件为
attacking == false,如果需要动画播放完成后再回切,勾选 Has Exit Time,将 Exit Time 值设为 1(即动画播放到100%进度时才允许触发过渡),过渡的固定持续时间设为0.1秒左右,保证切换流畅 - 检查 idle → swing 的过渡连线:取消不必要的 Has Exit Time 勾选,保证鼠标按下后立刻触发挥击动画,没有多余等待
- 运行时实时校验
进入运行模式后打开 Animator 窗口,实时观察两个指标: - swing 状态的动画归一化进度
normalizedTime是否顺利走到1 attacking布尔参数是否在挥击动画播完后自动切回 false,不需要依赖鼠标抬起动作
注意:如果 swing 到 idle 的过渡同时勾选了 Exit Time 和
attacking == false的条件,会出现两个条件同时满足才触发过渡的逻辑,必须根据需求二选一:要么靠 Exit Time 等动画播完自动切回,要么靠参数复位触发切回。
内容的提问来源于stack exchange,提问作者Marko Vuger
相关产品推荐
相关产品推荐

