Unity跑酷游戏动画切换循环异常及角色移动问题求助
跑酷游戏角色跑停异常与动画切换问题
我制作了一款跑酷游戏,设定为按住鼠标左键时角色奔跑,松开则停止。但实际运行时,按住鼠标左键期间,角色会出现跑-停-反复奔跑的异常,Run动画与Idle动画也会不断切换。
角色移动代码
using UnityEngine; public class StickmanMover : MonoBehaviour { [SerializeField] private float _maxSpeed; [SerializeField] private float _speed; private Rigidbody _rigidbody; private void Start() { _rigidbody = GetComponent<Rigidbody>(); } private void Update() { if (Input.GetKey(KeyCode.Mouse0) && _rigidbody.velocity.magnitude < _maxSpeed) { _rigidbody.AddForce(Vector3.forward * _speed * Time.deltaTime); } } }
动画控制代码
using UnityEngine; public class StickmanAnimator : MonoBehaviour { private Animator _animator; private void Start() { _animator = GetComponent<Animator>(); } private void Update() { if (Input.GetKey(KeyCode.Mouse0)) { _animator.SetTrigger("Run"); } else { _animator.SetTrigger("Idle"); } } }
动画过渡设置截图


问题根源
- 动画控制逻辑错误:
SetTrigger会在每帧调用时触发一次,且Trigger参数会自动重置。按住鼠标时,每帧都触发Run Trigger,加上动画过渡的条件设置,会导致动画在Run和Idle之间反复切换。 - 移动逻辑的边界波动:当角色速度接近
_maxSpeed时,_rigidbody.velocity.magnitude < _maxSpeed会频繁在true和false之间切换,导致AddForce时断时续,角色速度不稳定,视觉上呈现跑停交替。
修复方案
1. 替换动画触发方式(核心修复)
将SetTrigger改为SetBool,因为Bool参数可以持续保持状态,不会每帧触发切换:
修改后的动画控制代码:
using UnityEngine; public class StickmanAnimator : MonoBehaviour { private Animator _animator; // 使用StringToHash避免字符串查找开销 private static readonly int IsRunning = Animator.StringToHash("IsRunning"); private void Start() { _animator = GetComponent<Animator>(); } private void Update() { bool isMouseHeld = Input.GetKey(KeyCode.Mouse0); _animator.SetBool(IsRunning, isMouseHeld); } }
同时在Animator控制器中做以下调整:
- 删除原有的
Run和IdleTrigger参数,添加一个Bool类型的IsRunning参数 - 设置Idle到Run的过渡条件:
IsRunning == true - 设置Run到Idle的过渡条件:
IsRunning == false - 可适当调整过渡的
Exit Time和Fixed Duration,避免过渡过于突兀
2. 优化移动逻辑
解决速度接近_maxSpeed时的加力波动问题,推荐两种方式:
方式一:使用目标速度加速度控制(更平滑)
using UnityEngine; public class StickmanMover : MonoBehaviour { [SerializeField] private float _maxSpeed; [SerializeField] private float _acceleration; // 加速度,控制加速快慢 private Rigidbody _rigidbody; private void Start() { _rigidbody = GetComponent<Rigidbody>(); } // 物理逻辑建议放在FixedUpdate,与物理帧同步 private void FixedUpdate() { if (Input.GetKey(KeyCode.Mouse0)) { _rigidbody.drag = 0; // 奔跑时关闭拖拽 Vector3 targetVelocity = Vector3.forward * _maxSpeed; // 计算需要的力来趋近目标速度 Vector3 force = (targetVelocity - _rigidbody.velocity) * _acceleration; _rigidbody.AddForce(force, ForceMode.Acceleration); } else { _rigidbody.drag = 5f; // 松开鼠标时增加拖拽减速 } } }
方式二:给速度判断加阈值(简单修改)
private void Update() { // 增加0.1的阈值,避免速度在_maxSpeed附近波动时频繁开关加力 if (Input.GetKey(KeyCode.Mouse0) && _rigidbody.velocity.magnitude < _maxSpeed - 0.1f) { _rigidbody.AddForce(Vector3.forward * _speed * Time.deltaTime); } }
内容的提问来源于stack exchange,提问作者user21403547
相关产品推荐
相关产品推荐

