为何OnTriggerEnter2D会被非触发器碰撞体触发且重复执行两次
问题根因
- 你使用的玩家对象挂载了2个Collider2D,根据Unity 2D的碰撞触发规则:只要碰撞双方任意一方的碰撞体勾选了
isTrigger,且满足层级碰撞设置,就会向双方挂载的所有MonoBehaviour发送OnTriggerEnter2D消息。玩家的两个碰撞体(无论自身是否为触发器)和掉落物的触发器碰撞体接触时,会各自触发一次事件,因此逻辑执行了两次。 Destroy方法不会立即销毁对象,会等待当前帧的所有逻辑执行完成后才销毁对象,因此第一次执行销毁后,第二次触发的判断逻辑仍然可以访问到未被销毁的掉落物对象,判断条件依然成立。
可行解决方案
方案1:给掉落物添加拾取状态标记(最便捷)
在DroppedItem脚本中新增拾取状态字段,处理拾取逻辑前先校验状态,避免重复处理:
// 先修改DroppedItem类,新增字段 public class DroppedItem : MonoBehaviour { public Item item; public int itemAmount; // 新增拾取状态标记,默认未拾取 private bool _isPicked = false; public bool IsPicked => _isPicked; public void MarkPicked() { _isPicked = true; } } // 再修改你的触发逻辑 private void OnTriggerEnter2D(Collider2D other) { DroppedItem item = other.GetComponent<DroppedItem>(); if (item != null && other.isTrigger && !item.IsPicked) { item.MarkPicked(); Debug.Log("Picked up item."); inventory.AddItem(item.item, item.itemAmount); Destroy(item.gameObject); } }
方案2:通过层级过滤避免重复触发
将玩家的两个碰撞体分配到不同层级:
- 处理常规碰撞的非触发器碰撞体分配到
Player层 - 处理受击、拾取的触发器碰撞体分配到独立的
PlayerInteraction层
在Unity的项目设置-物理2D-碰撞矩阵中,设置掉落物所在的层级仅能和PlayerInteraction层触发碰撞,即可避免玩家的常规碰撞体和掉落物触发事件。
方案3:分离碰撞体的挂载对象
将玩家的受击/拾取触发器单独挂载到玩家的子对象上,把拾取逻辑也移到该子对象的脚本中,只有该子对象的触发器产生碰撞时才会执行拾取逻辑,不会受到主对象常规碰撞体的影响。
内容的提问来源于stack exchange,提问作者TahaSener07
相关产品推荐
相关产品推荐

