如何在玩家仅使用Character Controller时实现被其他物体推动?
仅用Character Controller实现被碰撞推动的方案
当然可以实现,核心思路是利用Character Controller的碰撞回调手动计算推力并应用移动,以下是两种可行方案:
方案一:响应带Rigidbody的物体推力
利用OnControllerColliderHit回调捕获碰撞信息,提取碰撞物体的移动方向,将其转换为玩家的位移向量后,调用CharacterController.Move()方法实现被推动效果。
示例代码:
using UnityEngine; public class PushablePlayer : MonoBehaviour { private CharacterController _charController; [SerializeField] private float pushIntensity = 6f; // 控制被推动的力度 void Awake() { _charController = GetComponent<CharacterController>(); } void OnControllerColliderHit(ControllerColliderHit hit) { // 只响应带非运动学Rigidbody的物体 Rigidbody hitRb = hit.collider.attachedRigidbody; if (hitRb == null || hitRb.isKinematic) return; // 过滤垂直方向的力,避免玩家被向上/向下推 Vector3 pushDirection = new Vector3(hit.moveDirection.x, 0f, hit.moveDirection.z); // 结合碰撞物体的质量计算推力,让重物体推动效果更明显 pushDirection *= pushIntensity * hitRb.mass; // 应用推力到玩家 _charController.Move(pushDirection * Time.deltaTime); } }
细节调整
- 如果需要更真实的物理反馈,可以用
hit.relativeVelocity替代hit.moveDirection,基于碰撞的相对速度计算推力 - 调整
pushIntensity参数适配不同场景的推动力度需求
方案二:响应静态/无Rigidbody物体的碰撞推动
如果碰撞对象是静态物体(比如场景中未添加Rigidbody的箱子),可以通过检测碰撞接触点,计算玩家需要偏移的方向:
示例代码:
using UnityEngine; public class StaticPushHandler : MonoBehaviour { private CharacterController _charController; [SerializeField] private float pushDistance = 0.1f; void Awake() { _charController = GetComponent<CharacterController>(); } void OnControllerColliderHit(ControllerColliderHit hit) { // 只处理无Rigidbody的静态碰撞体 if (hit.collider.attachedRigidbody != null) return; // 计算远离碰撞物体的方向 Vector3 pushDir = hit.normal * pushDistance; // 应用偏移,避免玩家卡在静态物体上同时实现被"推开"的效果 _charController.Move(pushDir * Time.deltaTime); } }
注意事项
- 确保CharacterController的
Slope Limit和Step Offset参数设置合理,避免推力导致玩家出现卡顿或穿模 - 可以结合两种方案,让玩家同时响应动态和静态物体的碰撞推动
内容的提问来源于stack exchange,提问作者thehelaeper67
相关产品推荐
相关产品推荐

