Unity角色移动Bug:碰撞障碍物后侧移触发突然前冲
问题分析与解决方案
问题根源
你维护的movementVelocity变量和CharacterController的实际移动状态脱节了。当角色撞到箱子时,CharacterController的实际速度(characterController.velocity)会被碰撞约束限制,但你自己的movementVelocity还在持续向目标速度(向前)逼近。等你侧移脱离箱子后,这个被“憋住”的速度会瞬间生效,导致突然冲刺。
修复方案
每次更新移动逻辑前,先将movementVelocity同步为CharacterController的实际水平速度,确保我们的速度变量和角色真实移动状态一致。
修改后的PlayerMovement类代码:
public class PlayerMovement : MonoBehaviour { [SerializeField] private CharacterController characterController; [SerializeField] private TextMeshProUGUI speedText; private Vector3 movementDirection; private Vector3 movementVelocity; [SerializeField] private float accelerationSpeed = 5f; [SerializeField] private float decelerationSpeed = 5f; [SerializeField] private float movementSpeed = 20f; private void Awake() { characterController = GetComponent<CharacterController>(); } public void Move(Vector2 direction) { movementDirection = new Vector3(direction.x, 0f, direction.y); } public void Stop() { movementDirection = Vector3.zero; } private void Update() { // 同步movementVelocity为CharacterController的实际水平速度,排除Y轴重力影响 movementVelocity = new Vector3(characterController.velocity.x, 0f, characterController.velocity.z); if (movementDirection.magnitude > 0) { Vector3 desiredVelocity = movementDirection.normalized * movementSpeed; movementVelocity = Vector3.MoveTowards(movementVelocity, desiredVelocity, accelerationSpeed * Time.deltaTime); } else { movementVelocity = Vector3.MoveTowards(movementVelocity, Vector3.zero, decelerationSpeed * Time.deltaTime); } Vector3 movement = transform.TransformDirection(movementVelocity) * Time.deltaTime; characterController.Move(movement); speedText.text = characterController.velocity.magnitude.ToString("0.##"); } }
关键修改说明
- 在Update开头添加了
movementVelocity与characterController.velocity的同步逻辑,只保留X/Z轴的水平速度(忽略Y轴的重力或跳跃速度) - 后续的加速/减速计算都基于同步后的真实速度,避免了“虚拟速度”累积的问题
- 这样当角色被障碍物阻挡时,
movementVelocity会被同步为实际的低速(或0),不会再累积未生效的向前速度
内容的提问来源于stack exchange,提问作者Ajiva
相关产品推荐
相关产品推荐

