Unity实现同类型对象碰撞体互相忽略碰撞的方法
解决方案
先把你现在的设置问题说清楚:别给敌人碰撞体开Is Trigger = true。
这个属性勾上之后,碰撞体就变成纯触发器了,完全不会产生物理阻挡、推挤效果,和任何物体碰上去都只会触发OnTriggerEnter/Stay/Exit回调,根本挡不住,这就是你所有敌人跑着跑着全叠一块的根本原因。
要实现选择性忽略某类碰撞、剩下的碰撞保持正常物理效果,两种方案随便选,优先用第一种,性能最好。
方案1:用Layer层统一配置碰撞规则(首推,零运行时开销)
这是Unity原生做的批量碰撞过滤,不用写多余代码,规则固定的话用这个最省事:
- 打开
Edit -> Project Settings -> Tags and Layers,新建一个专门给敌人用的层,比如叫Enemy - 把所有敌方对象的Layer都改成刚建的
Enemy - 打开
Edit -> Project Settings -> Physics 2D,找到最下面的Layer Collision Matrix(层碰撞矩阵):- 如果你要的是敌人之间不堆叠、能互相挡住,但是可以穿过所有不是敌人的物体(墙、道具、甚至玩家):找到
Enemy对应的行和列,把Enemy和其他所有非Enemy层的勾选全取消,只留Enemy和Enemy的勾就行。这样敌人只会和同层的其他敌人产生碰撞阻挡,碰到其他层的东西直接穿过去,不会被卡。 - 如果你确实要敌人之间能互相穿、不产生碰撞,但是碰到非敌人的物体会正常被挡住:只需要把
Enemy层和Enemy层对应的勾取消,其他层的勾保留就好。
- 如果你要的是敌人之间不堆叠、能互相挡住,但是可以穿过所有不是敌人的物体(墙、道具、甚至玩家):找到
方案2:用Physics2D.IgnoreCollision()动态设置
如果你的敌人是运行时动态生成的,或者碰撞规则需要实时变,就用这个API,用法没你想的复杂:
- 方法签名:
Physics2D.IgnoreCollision(Collider2D a, Collider2D b, bool ignore = true) - 逻辑很简单:第三个参数传
true,就告诉物理系统a和b这两个碰撞体之间不要算碰撞,碰到了直接穿,既不会有物理推挤,也不会触发碰撞相关回调;传false就恢复正常碰撞。 - 给个现成的参考代码,挂在敌人预制体上就行,下面的例子是生成敌人时自动忽略所有敌人之间的碰撞,如果你要反过来忽略和非敌人的碰撞,改个判断条件就可以:
using UnityEngine; using System.Collections.Generic; public class Enemy : MonoBehaviour { // 全局存所有活着的敌人的碰撞体 private static readonly List<Collider2D> _allEnemyCols = new List<Collider2D>(); private Collider2D _myCol; private void Awake() { _myCol = GetComponent<Collider2D>(); // 和已经存在的所有敌人都设置忽略碰撞 foreach (var otherCol in _allEnemyCols) { Physics2D.IgnoreCollision(_myCol, otherCol, true); } _allEnemyCols.Add(_myCol); } private void OnDestroy() { // 敌人死了就从列表里删掉 _allEnemyCols.Remove(_myCol); } }
提个醒:这个API只改两个传入碰撞体之间的碰撞规则,不会改碰撞体本身的
Is Trigger状态,也不会影响这两个碰撞体和其他对象的碰撞逻辑。
内容的提问来源于stack exchange,提问作者George Zyn
相关产品推荐
相关产品推荐

