常用的碰撞检测有三种。
基础碰撞检测
第一种就是最基础的碰撞检测,两个碰撞体之间碰撞,会自动触发碰撞检测方法
cs
private void OnCollisionEnter2D(Collision2D other) {
// 开始碰撞
}
private void OnCollisionStay2D(Collision2D other) {
// 碰撞过程中
}
private void OnCollisionExit2D(Collision2D other) {
// 碰撞结束
}
如果碰撞双方有任意一个勾选Is Trigger 或碰撞双方均勾选Is Trigger,那么就不会执行上面的碰撞检测,而是执行OnTriggerEnter2D/Stay2D/Exit2D;
射线检测
对于上面的基础碰撞检测,只能满足一些简单的功能,复杂一点的检测,就不太好处理(但并不是不能处理)。
比如我们要做一款消逝的光芒2D版游戏,人物在跑酷过程中,会从一个屋顶跳跃到另一个屋顶,由于屋顶和屋顶之间的距离比较远,人物在跳跃时,很可能要经历下面这个阶段:跳过去,并在下落的过程中抓住屋檐,随后攀爬上去。我们希望,在人物下落的过程中,如果距离屋檐比较近,且按下空格键,也视为抓住了屋檐。
这个时候,如果仅凭借基础碰撞,就必须要求人物和屋檐发生碰撞,这样的判断过于严苛。当然我们也可以通过另一种方式实现。在人物原本的碰撞体外面,再添加更大的一层碰撞体,并勾选这个更大碰撞体为触发器。当触发器和屋檐发生碰撞检测并执行OnTriggerEnter2D/Stay2D/Exit2D方法时,就视为人物抓住了屋檐。
这种时候,选用射线检测不失为一种更好的方式。
射线检测很好理解,就是从物体上发射一条射线,被射线射中就说明发生了碰撞。
cs
/**
* origin 第一个参数是需要检测碰撞的对象,在消逝的光芒2D中,第一个参数就是玩家的位置
* direction 第二个参数是射线的方向,比如检测玩家的正前方
* distance 第三个参数是射线的长度
* layerMask 第四个参数是射线会检测玩家和哪一层的碰撞
*/
public static RaycastHit2D Raycast(
Vector2 origin,
Vector2 direction,
float distance,
int layerMask
);
这里的距离要根据是实际情况来决定,比如设置的太短,碰撞双方就必须很近才会触发碰撞;如果设置的太长,有可能会出现玩家距离屋檐很远却可以攀到屋檐上
下面是一个实际的代码举例
cs
RaycastHit2D collisionCheck = Physics2D.Raycast(
capsuleCollider.bounds.center,
Vector2.left,
capsuleCollider.bounds.size.x / 2 + radius / 2,
LayerMask.GetMask("Ground")
);
上面这段代码的第一个参数是某个变量名为capsuleCollider的碰撞体中心,这行代码正在检测相对于这个中心的碰撞。第二个参数表明射线方向朝左。第三个参数表明射线的长度是capsuleCollider.bounds.size.x / 2 + radius / 2。这行代码的计算结果表示,以碰撞体中心为端点,以Vector2.left为射线,长度在[0, capsuleCollider.bounds.size.x / 2 + radius / 2]范围内,且属于Ground层(第四个参数)的其他物体会与当前物体发生碰撞检测
范围检测
除了射线检测,还有一种很像射线检测的方式,就是范围检测,它比射线检测还要灵活,可以在平面内的任意一个位置进行碰撞检测。
cs
/**
* point 平面内的点
* radius 以point点为圆心的半径
* layerMask 检测玩家和哪一层的碰撞
*/
public static Collider2D OverlapCircle(Vector2 point, float radius, int layerMask);
仍然以上面为例
cs
Collider2D c = Physics2D.OverlapCircle(
new Vector2(
capsuleCollider.bounds.center.x - capsuleCollider.bounds.size.x / 2,
capsuleCollider.bounds.center.y
),
0.1F,
LayerMask.GetMask("Ground")
);
第一个参数是一个Vector2,用来表示平面内的点;第二个参数是0.1F,表示以第一个参数为圆心的半径;属于Ground层(第三个参数)的其他物体会与当前物体发生碰撞检测