Unity 3D中如何在Character Controller里实现OnCollisionExit?
在OnControllerColliderHit中实现类似OnCollisionEnter/Exit的功能
核心问题说明
OnControllerColliderHit 仅会在控制器与碰撞体接触的每一帧触发,没有内置的碰撞退出回调。要实现"碰撞显示、离开隐藏"的效果,需要手动跟踪当前接触的目标对象状态。
解决方案代码
using UnityEngine; using System.Collections.Generic; public class PlayerCollision : MonoBehaviour { public PlayerMovement movement; [SerializeField] GameObject _toggleObject; // 存储当前正在接触的障碍物对象,自动去重 private HashSet<GameObject> _currentObstacles = new HashSet<GameObject>(); private void OnControllerColliderHit(ControllerColliderHit hit) { if (hit.gameObject.CompareTag("Obstacle")) { // 将接触的障碍物加入集合 _currentObstacles.Add(hit.gameObject); // 激活目标物体 _toggleObject.SetActive(true); } } private void Update() { // 清理集合中已销毁的对象,避免内存泄漏 _currentObstacles.RemoveWhere(obj => obj == null); // 如果没有接触任何障碍物,隐藏目标物体 if (_currentObstacles.Count == 0) { _toggleObject.SetActive(false); } } private void OnDisable() { // 对象禁用时清空集合,防止残留数据 _currentObstacles.Clear(); } }
代码逻辑解释
- HashSet跟踪接触对象:用
HashSet<GameObject>存储当前接触的障碍物,避免同一对象重复添加,确保状态准确。 - OnControllerColliderHit处理碰撞中状态:每次检测到与障碍物接触时,将对象加入集合并激活显示物体。
- Update检测退出状态:每帧检查集合,若集合为空(无任何障碍物接触),则隐藏显示物体;同时清理已销毁的对象,避免无效引用。
- OnDisable清理数据:对象禁用或场景切换时清空集合,防止残留状态影响后续逻辑。
额外注意事项
- 确保CharacterController的
Skin Width和Min Move Distance参数设置合理,避免因控制器抖动导致的状态频繁切换。 - 如果需要更精确的碰撞进入/退出时机,可以结合
Physics.OverlapCapsule(匹配CharacterController的碰撞范围)在Update中主动检测,但上述方案是适配OnControllerColliderHit的最直接实现方式。
内容的提问来源于stack exchange,提问作者Richard Johnson
相关产品推荐
相关产品推荐

