Unity中如何检测与禁用碰撞体的碰撞?维度切换场景需求
解决方案:检测禁用维度物体以阻止切换
禁用的GameObject不会参与任何物理检测,所以Raycast确实无法命中它们。这里提供两种可行的解决思路:
方法1:控制组件激活而非禁用整个GameObject
把原来的SetActive逻辑改成单独控制物体的渲染器和碰撞体组件,这样GameObject始终处于激活状态,物体的碰撞体可以用于检测,只是在非当前维度时不可见、不可交互。
代码示例:
public List<GameObject> redObjects; public List<GameObject> blueObjects; private bool seeingRed = false; private void Update() { if (Input.GetKeyDown(KeyCode.F)) { // 判断是否允许切换 bool canSwitch = true; if (!seeingRed) { // 要切换到红维度,检查玩家是否与红维度物体重叠 canSwitch = !IsPlayerOverlapping(redObjects); } else { // 要切换到蓝维度,检查玩家是否与蓝维度物体重叠 canSwitch = !IsPlayerOverlapping(blueObjects); } if (canSwitch) { seeingRed = !seeingRed; if (seeingRed) SetRedDimension(); else SetBlueDimension(); } } } // 检测玩家是否与目标维度的物体重叠 private bool IsPlayerOverlapping(List<GameObject> targetObjects) { Collider playerCollider = GetComponent<Collider>(); foreach (var obj in targetObjects) { Collider objCollider = obj.GetComponent<Collider>(); if (objCollider != null && playerCollider.bounds.Intersects(objCollider.bounds)) { return true; } } return false; } // 切换到红维度 public void SetRedDimension() { ToggleDimensionObjects(redObjects, true); ToggleDimensionObjects(blueObjects, false); } // 切换到蓝维度 public void SetBlueDimension() { ToggleDimensionObjects(redObjects, false); ToggleDimensionObjects(blueObjects, true); } // 统一控制维度物体的渲染和碰撞 private void ToggleDimensionObjects(List<GameObject> objects, bool isActive) { foreach (var obj in objects) { if (obj.TryGetComponent(out MeshRenderer renderer)) { renderer.enabled = isActive; } if (obj.TryGetComponent(out Collider collider)) { collider.enabled = isActive; } } }
优点:物体移动时,碰撞体的Bounds会自动更新,检测结果始终准确;后续扩展维度功能更灵活。
缺点:需要确保所有维度物体都有MeshRenderer和Collider组件(可以用TryGetComponent避免空引用)。
方法2:预存禁用物体的碰撞范围
如果必须保持SetActive禁用整个GameObject的逻辑,可以在游戏启动时预存所有维度物体的碰撞范围(Bounds),切换前直接用玩家的Bounds和预存范围做重叠检测。
代码示例:
public List<GameObject> redObjects; public List<GameObject> blueObjects; private bool seeingRed = false; private List<Bounds> redBounds = new List<Bounds>(); private List<Bounds> blueBounds = new List<Bounds>(); private void Start() { // 预存红维度物体的碰撞范围 foreach (var obj in redObjects) { if (obj.TryGetComponent(out Collider collider)) { redBounds.Add(collider.bounds); } } // 预存蓝维度物体的碰撞范围 foreach (var obj in blueObjects) { if (obj.TryGetComponent(out Collider collider)) { blueBounds.Add(collider.bounds); } } } private void Update() { if (Input.GetKeyDown(KeyCode.F)) { bool canSwitch = true; Collider playerCollider = GetComponent<Collider>(); if (!seeingRed) { // 检查玩家是否与红维度物体的预存范围重叠 foreach (var bounds in redBounds) { if (playerCollider.bounds.Intersects(bounds)) { canSwitch = false; break; } } } else { // 检查玩家是否与蓝维度物体的预存范围重叠 foreach (var bounds in blueBounds) { if (playerCollider.bounds.Intersects(bounds)) { canSwitch = false; break; } } } if (canSwitch) { seeingRed = !seeingRed; if (seeingRed) setRed(); else setBlue(); } } } // 保留原来的维度切换逻辑 public void setRed() { redObjects.ForEach(obj => obj.SetActive(true)); blueObjects.ForEach(obj => obj.SetActive(false)); } public void setBlue() { redObjects.ForEach(obj => obj.SetActive(false)); blueObjects.ForEach(obj => obj.SetActive(true)); }
优点:不需要修改原来的SetActive切换逻辑;适合物体位置固定的场景。
缺点:如果维度物体会移动,需要在物体移动时实时更新对应的Bounds列表,否则检测结果会失效。
内容的提问来源于stack exchange,提问作者Adrian Soares
相关产品推荐
相关产品推荐

