Unity中OnTriggerStay2D()因其他物体触发OnTriggerExit2D()失效
故障根本原因
现有逻辑存在两个核心缺陷:
- 状态判断逻辑没有绑定具体碰撞体:
OnTriggerExit2D回调只要检测到任意带PuzzlePiece标签的物体离开,就直接把isCovered全局置为false,完全不校验离开的是不是原本放在瓦片上的那块拼图,也不检查碰撞区域内是否还有其他已放置的拼图块。 - 对Unity 2D物理触发逻辑的认知偏差:当触发器区域内同时存在多个碰撞体时,只要其中一个碰撞体触发退出事件,Unity不会自动为剩余留在区域内的碰撞体持续触发
OnTriggerStay2D回调,必须等对应碰撞体重新进入触发器范围才会恢复Stay调用。这就是为什么路过的拼图离开后,就算原本放好的拼图还在碰撞区,OnTriggerStay2D也不会再执行把状态改回true。
修复方案
不要用单个布尔值直接标记覆盖状态,改为维护当前触发区域内所有符合条件的已放置拼图集合,通过集合是否为空判断覆盖状态,具体调整点:
- 用
HashSet存储当前处于传感器范围内、且isPlaced为true的拼图块引用,避免重复记录 - 三个触发器回调只针对当前触发事件的碰撞体做增删操作,不直接修改全局覆盖标记
- 将
isCovered改为只读属性,实时返回集合元素数量是否大于0 - 补充
OnTriggerEnter2D逻辑,避免拼图刚进入区域时第一帧的状态丢失
修复后的完整代码如下:
using System.Collections.Generic; using UnityEngine; public class GridTileSensor : MonoBehaviour { private readonly HashSet<GameObject> _placedPiecesInSensor = new HashSet<GameObject>(); // 实时判断是否处于覆盖状态 public bool isCovered => _placedPiecesInSensor.Count > 0; private void OnTriggerEnter2D(Collider2D collision) { CheckAndAddPiece(collision); } private void OnTriggerStay2D(Collider2D collision) { if (!collision.gameObject.CompareTag("PuzzlePiece")) return; Dragger pieceDragger = collision.gameObject.GetComponent<Dragger>(); if (pieceDragger.isPlaced) { _placedPiecesInSensor.Add(collision.gameObject); } else { // 处理已放置的拼图被玩家重新拿起拖动的情况 _placedPiecesInSensor.Remove(collision.gameObject); } } private void OnTriggerExit2D(Collider2D collision) { if (collision.gameObject.CompareTag("PuzzlePiece")) { // 仅移除当前离开的拼图块,不影响区域内其他拼图 _placedPiecesInSensor.Remove(collision.gameObject); } } private void CheckAndAddPiece(Collider2D collision) { if (!collision.gameObject.CompareTag("PuzzlePiece")) return; Dragger pieceDragger = collision.gameObject.GetComponent<Dragger>(); if (pieceDragger.isPlaced) { _placedPiecesInSensor.Add(collision.gameObject); } } }
优化提示:可以给拼图块提前缓存
Dragger组件引用,避免每帧调用GetComponent产生不必要的性能开销,不影响核心逻辑修复。
内容的提问来源于stack exchange,提问作者Egemen Ulucam
相关产品推荐
相关产品推荐

