Unity玩家动画未按编程逻辑在Idle与Walk间异常切换问题
问题现象
- 按住D键控制玩家移动时,Walk动画无法持续播放,在Idle与Walk状态间反复切换
- 单独预览Idle、Walk单个动画片段无异常
- 状态过渡会从Idle状态启动后才切换至Walk状态,新建项目重写整套逻辑问题仍复现
原实现代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { [SerializeField] float moveForce = 10f; [SerializeField] float jumpForce = 11f; float movementX; Rigidbody2D myBody; Animator Anim; private SpriteRenderer sr; string WALK_ANIMATION = "Walk"; private void Update() { playerMoveKeyboard(); animatePlayer(); } private void Awake() { myBody = GetComponent<Rigidbody2D>(); Anim = myBody.GetComponent<Animator>(); sr = GetComponent<SpriteRenderer>(); } void playerMoveKeyboard() { movementX = Input.GetAxisRaw("Horizontal"); transform.position += new Vector3(movementX, 0f, 0f) * moveForce * Time.deltaTime; } void animatePlayer() { if(movementX > 0) { Anim.SetBool(WALK_ANIMATION, true); sr.flipX = false; } else if (movementX < 0) { Anim.SetBool(WALK_ANIMATION, true); sr.flipX = true; } else { Anim.SetBool(WALK_ANIMATION, false); } } }
问题根因
动画异常跳变由两个问题共同导致:
- Animator状态机过渡配置错误:Idle与Walk的双向过渡勾选了Has Exit Time(存在退出时间)。当Walk动画播放到设定的退出时间节点时会自动触发状态校验,即使Walk布尔参数持续为true,也会短暂切回Idle状态;切回Idle后检测到Walk参数仍为true,又会再次切回Walk,最终形成反复切换的抖动效果。
- 代码组件获取逻辑存在隐患:原代码通过Rigidbody2D组件调用
GetComponent<Animator>()获取动画组件,虽然组件都挂在同一物体上时能正常运行,但后续如果调整对象层级结构(比如将动画、渲染组件移到子节点),会直接出现空引用报错。
修复方案
1. 修正Animator状态机配置
- 打开Animator窗口,分别选中Idle→Walk、Walk→Idle两个过渡箭头
- 在Inspector面板取消勾选Has Exit Time
- 将*Transition Duration(s)(过渡时长)*调整为0~0.1之间的数值,避免动画硬切过于突兀
- 确认过渡条件配置无多余项:
- Idle→Walk过渡:仅保留条件为
Walk参数等于true - Walk→Idle过渡:仅保留条件为
Walk参数等于false
- Idle→Walk过渡:仅保留条件为
- 分别选中Idle、Walk两个动画片段,在Inspector面板确认勾选Loop Time(循环时间),保证动画可正常循环播放
2. 修正代码逻辑
优化组件获取方式,简化动画判断逻辑,修复后完整代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { [SerializeField] float moveForce = 10f; [SerializeField] float jumpForce = 11f; float movementX; Rigidbody2D myBody; Animator anim; SpriteRenderer sr; const string WALK_ANIMATION = "Walk"; private void Awake() { myBody = GetComponent<Rigidbody2D>(); // 直接获取当前物体上的Animator组件,避免通过其他组件中转查找带来的引用异常 anim = GetComponent<Animator>(); sr = GetComponent<SpriteRenderer>(); } private void Update() { PlayerMoveKeyboard(); AnimatePlayer(); } void PlayerMoveKeyboard() { movementX = Input.GetAxisRaw("Horizontal"); transform.position += new Vector3(movementX, 0f, 0f) * moveForce * Time.deltaTime; } void AnimatePlayer() { bool isWalking = movementX != 0; anim.SetBool(WALK_ANIMATION, isWalking); // 仅在有移动输入时调整角色朝向,避免静止状态下不必要的翻转 if (movementX != 0) { sr.flipX = movementX < 0; } } }
内容的提问来源于stack exchange,提问作者Lleyton Bell
相关产品推荐
相关产品推荐

