Unity2D开发入门-Collider 碰撞体与碰撞检测

前言

在Unity2D中,有多个Collider组件可用于进行碰撞检测和物体交互。以下是一些常用的Collider组件及其功能介绍:

  1. Box Collider 2D(盒碰撞器):创建一个矩形的碰撞器,可以通过设置大小属性来定义碰撞器的宽度和高度。
  2. Circle Collider 2D(圆形碰撞器):创建一个圆形的碰撞器,可以通过设置半径属性来定义圆的大小。
  3. Polygon Collider 2D(多边形碰撞器):创建一个自定义形状的碰撞器,可以通过添加多边形的顶点来定义一个复杂的碰撞形状。
  4. Edge Collider 2D(边缘碰撞器):创建一个由一系列直线段组成的碰撞器,用于定义边缘、墙壁或地图的碰撞形状。
  5. Capsule Collider 2D(胶囊碰撞器):创建一个胶囊形状的碰撞器,可以通过设置半径和高度属性来定义胶囊的大小。
  6. Composite Collider 2D(复合碰撞器):用于合并多个碰撞器为单个碰撞器,可以优化性能,尤其在大型地图等情况下。

以上是Unity2D中常用的Collider组件,每个碰撞器都有其特定的用途和适用场景。选择适当的碰撞器类型取决于你的需求,例如对象的形状、精确性要求和性能要求等。要在对象上添加Collider组件,可以通过Unity编辑器的组件面板或使用代码进行手动添加。碰撞器通常与刚体(Rigidbody)组件一起使用,以实现物体之间的物理交互和碰撞检测。

碰撞的检测方法

在Unity中,碰撞检测是指在场景中检测物体之间是否发生碰撞的过程。Unity提供了多种方式来进行碰撞检测:

  1. 刚体碰撞检测:通过给物体添加刚体组件(Rigidbody),可以启用物体之间的物理交互和碰撞检测。

    当两个带有刚体组件的物体发生碰撞时,Unity会自动进行碰撞检测,并触发相应的碰撞事件(如OnCollisionEnter、OnCollisionStay、OnCollisionExit等),供开发者处理。

  2. Trigger触发器:Trigger是一种特殊的碰撞器(如Collider组件的isTrigger属性设为true),用于检测物体之间的接触,而不需要物体发生物理交互。

    当一个物体与Trigger碰撞器接触时,会触发相应的事件(如OnTriggerEnter、OnTriggerStay、OnTriggerExit等),供开发者处理。

  3. 物理射线检测:使用物理射线(Physics.Raycast、Physics2D.Raycast)可以发射一条射线来检测是否与场景中的物体发生碰撞。根据射线与物体的交点,可以进行进一步的处理。

  4. Overlap检测:使用Overlap系列函数(如Physics.CheckSphere、Physics.OverlapBox、Physics2D.OverlapCircle等)可以检测特定形状的区域内是否存在物体。这些函数可以返回与指定区域重叠的物体列表,供开发者进一步处理。

  5. 物理材质和碰撞层:通过为物体设置不同的物理材质和碰撞层,可以控制物体之间的碰撞检测和行为。物理材质可以影响碰撞的摩擦力、弹性等属性,碰撞层可以决定哪些物体会发生碰撞。

无论使用哪种碰撞检测方式,都需要在物体上添加对应的碰撞器组件(如Box Collider、Circle Collider等),以及处理相应的碰撞事件。开发者可以在碰撞事件中编写自定义的逻辑,例如触发特定的游戏事件、修改物体属性等。

使用触发器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void OnTriggerEnter2D(Collider2D col)
{

}

private void OnTriggerExit2D(Collider2D col)
{

}

private void OnTriggerStay2D(Collider2D col)
{

}

在Unity中,2D触发器(Trigger)有以下几个相关的方法:

  1. OnTriggerEnter2D(Collider2D other):
    • 作用:当有物体的碰撞器进入触发器时被调用。
    • 参数:other是进入触发器的碰撞器。
  2. OnTriggerStay2D(Collider2D other):
    • 作用:当有物体的碰撞器停留在触发器内时被调用(每一帧调用)。
    • 参数:other是停留在触发器内的碰撞器。
  3. OnTriggerExit2D(Collider2D other):
    • 作用:当有物体的碰撞器离开触发器时被调用。
    • 参数:other是离开触发器的碰撞器。

刚性碰撞检测

Unity中有多种方法可以进行碰撞检测。

以下是一些常用的方法及示例:

OnCollisionEnter(Collision2D collision)
当物体首次接触到其他物体时触发该方法。

1
2
3
4
5
6
7
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
Debug.Log("碰到了玩家!");
}
}

OnCollisionStay2D(Collision2D collision)
当物体与其他物体持续接触时触发该方法。

1
2
3
4
5
6
7
void OnCollisionStay2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
Debug.Log("与敌人持续碰撞中!");
}
}

OnCollisionExit2D(Collision2D collision)
当物体与其他物体分离时触发该方法。

1
2
3
4
5
6
7
void OnCollisionExit2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Obstacle"))
{
Debug.Log("与障碍物分离!");
}
}

射线检测

使用射线检测两个点之间的碰撞情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 创建一个从 transform.position 开始的射线
Vector2 rayOrigin = this.transform.position;
Vector2 rayDirection = Vector2.right;
// 射线检测
RaycastHit2D hit = Physics2D.Raycast(
rayOrigin,
rayDirection,
100,
1 << LayerMask.NameToLayer("Enemy")
);
// 如果射线击中了碰撞体
if (hit)
{
// 获取击中的碰撞体
Collider2D collider = hit.collider;
// 获取击中点的坐标
Vector2 hitPoint = hit.point;
// 做出响应...
Debug.Log("射中敌人:" + collider.name + "位置:" + hitPoint.ToString());
}

周围检测

检测指定位置周围的碰撞体。

1
2
3
4
5
6
7
8
9
10
11
Collider2D[] colliders = Physics2D.OverlapCircleAll(
this.transform.position,
100
);
foreach (Collider2D collider in colliders)
{
if (collider.gameObject.CompareTag("Enemy"))
{
Debug.Log("发现敌人!");
}
}

设置layer

下面的写法和上面实现了同样的逻辑。

1
2
3
4
5
6
7
8
9
Collider2D[] colliders = Physics2D.OverlapCircleAll(
this.transform.position,
100,
1 << LayerMask.NameToLayer("Enemy")
);
foreach (Collider2D collider in colliders)
{
Debug.Log("发现敌人!");
}

根据名称获取layerMask

1
int layerMask

单个Layer

1
int layerMask = 1 << LayerMask.NameToLayer("Enemy");

设置多个Layer

1
2
3
int layerMask = 0;
layerMask |= 1 << LayerMask.NameToLayer("Enemy");
layerMask |= 1 << LayerMask.NameToLayer("Water");

刚体(Rigid Body 2D)

不同于 3D 刚体,2D 刚体具有以下三种类型:

Dynamic

物体会受到力的影响移动和旋转。

Kinematic

不受力的影响,只能通过代码让其动起来。
能和 Dynamic 2D 刚体产生碰撞,但是不会动,只会进入碰撞检测函数,因此没有质量、摩擦系数等属性。
性能消耗较低,主要是使用代码处理移动和旋转。

Static

完全不动的需要检测碰撞的对象,相当于时无限质量不可移动的对象,性能消耗最小,只能和 Dynamic 2D 刚体碰撞。

和它类似的有只加碰撞器而不加刚体的物体,它们会和刚体物体产生碰撞,但是自己不会动。

总结:

  1. Dynamic 动态刚体:受力的作用,要动要碰撞的对象。

  2. Kinematic 运动学刚体:通过刚体 API 移动的对象,不受力的作用,可以和Dynamic碰撞。

  3. Static 静态刚体:不动不受力作用的静态物体,可以和Dynamic碰撞。

Unity2D碰撞和触发

这里主要说2D游戏的碰撞和触发,和3D是不太一样的。

碰撞的生效条件

碰撞三要素:

  1. 碰撞发生在两个2D物体之间,两个物体设置了相互可碰撞(Layer Collision Matrix)。
  2. 碰撞双方都有碰撞体(都不能勾选触发器)。
  3. 发生碰撞的双方,至少一个是刚体(Rigidbody),另一个是刚体或运动学刚体,不能都是运动学刚体。

响应的事件

  • OnCollisionEnter2D(Collision2D collision) 开始碰撞
  • OnCollisionStay2D(Collision2D collision) 碰撞中
  • OnCollisionExit2D(Collision2D collision) 碰撞分离

注意

方法都是带有2D,不带2D的是3D的碰撞事件不会被触发。

Edit => Project Settings...

只有勾选了可碰撞关系的才会碰撞。

image-20230813235408231

触发的生效条件

触发的条件很宽松,有些是我们以为不能触发的实际也能触发的。

  1. 发生在两个2D物体之间,两个物体即使设置了不能碰撞也能触发。

  2. 双方其中一方设置了触发器,双方都会产生触发回调(即使没有设置为触发器的一方也能产生触发回调),不能双方都没有设置触发器。

  3. 即使双方都是运动学刚体也能触发。

响应的事件

  • OnTriggerEnter2D(Collider2D col) 开始触发
  • OnTriggerExit2D(Collider2D col) 触发中
  • OnTriggerStay2D(Collider2D col) 触发分离

这样也是可以触发的

image-20230813235039519