碰撞检测与触发事件

8.1 Collider 组件

Collider 定义物体的物理形状,用于碰撞检测。

3D Collider 类型

类型 用途
BoxCollider 盒型碰撞体(箱子、墙壁)
SphereCollider 球型碰撞体(球、检测范围)
CapsuleCollider 胶囊碰撞体(角色)
MeshCollider 网格碰撞体(复杂形状,性能消耗大)
TerrainCollider 地形碰撞体

2D Collider 类型

  • BoxCollider2D / CircleCollider2D / CapsuleCollider2D
  • PolygonCollider2D(多边形)
  • EdgeCollider2D(边缘线)

8.2 碰撞事件

碰撞需要两个物体都带有 Collider,且至少一个有 Rigidbody。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class CollisionEvents : MonoBehaviour
{
// 碰撞开始
private void OnCollisionEnter(Collision collision)
{
Debug.Log($"撞到了:{collision.gameObject.name}");
Debug.Log($"碰撞点数量:{collision.contactCount}");

// 获取第一个碰撞点
ContactPoint contact = collision.GetContact(0);
Debug.Log($"碰撞点位置:{contact.point}");
Debug.Log($"碰撞法线:{contact.normal}");
}

// 碰撞持续中
private void OnCollisionStay(Collision collision)
{
// 每帧调用,持续碰撞期间
}

// 碰撞结束
private void OnCollisionExit(Collision collision)
{
Debug.Log($"离开碰撞:{collision.gameObject.name}");
}
}

碰撞力计算

1
2
3
4
5
6
7
8
9
private void OnCollisionEnter(Collision collision)
{
// 碰撞冲量 → 计算伤害
float impactForce = collision.impulse.magnitude;
if (impactForce > 10f)
{
TakeDamage(impactForce);
}
}

8.3 触发器事件

将 Collider 的 IsTrigger 勾选后,变为触发器,不产生物理碰撞,仅触发事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class TriggerEvents : MonoBehaviour
{
// 进入触发器区域
private void OnTriggerEnter(Collider other)
{
Debug.Log($"进入区域:{other.gameObject.name}");

if (other.CompareTag("Player"))
{
CollectItem();
}
}

// 停留在触发器区域
private void OnTriggerStay(Collider other)
{
// 每帧调用,可用于伤害区域
}

// 离开触发器区域
private void OnTriggerExit(Collider other)
{
Debug.Log($"离开区域:{other.gameObject.name}");
}
}

触发器的典型应用

场景 实现
拾取道具 道具设为 Trigger,玩家进入触发拾取
伤害区域 岩浆/毒气区域,对进入者持续造成伤害
机关触发 玩家走到特定位置激活门/电梯
检测范围 AI 发现玩家的检测区域
关卡边界 检测物体是否掉出地图

8.4 Layer 与碰撞矩阵

通过 Layer 控制哪些层之间可以碰撞。

设置步骤

  1. 选中 GameObject,在 Inspector 顶部选择 Layer
  2. 点击 Layer 下拉菜单 → Add Layer… 添加自定义层级
  3. Edit → Project Settings → Physics → Layer Collision Matrix
1
2
3
4
5
6
7
8
9
// 运行时修改物体的 Layer
gameObject.layer = LayerMask.NameToLayer("Player");

// 忽略特定层之间的碰撞
Physics.IgnoreLayerCollision(
LayerMask.NameToLayer("Player"),
LayerMask.NameToLayer("Enemy"),
true
);

LayerMask 过滤器

1
2
3
4
5
6
// 只检测特定层
int layerMask = LayerMask.GetMask("Player", "Ground");
if (Physics.Raycast(ray, out hit, 100f, layerMask))
{
// 只与 Player 和 Ground 层碰撞
}

8.5 碰撞与触发的选择

碰撞 触发器
物理阻挡 是(物体不能穿过) 否(可穿过)
回调方法 OnCollision 系列 OnTrigger 系列
性能 较高(需计算物理反馈) 较低
典型用途 墙壁、地板、角色碰撞 拾取区、检测区、伤害区

8.6 本章小结

  • Collider 定义物理形状,Rigidbody + Collider 产生真实碰撞
  • OnCollisionEnter/Stay/Exit 处理碰撞事件
  • Trigger 不产生物理力,适合检测区域
  • Layer 和碰撞矩阵控制哪些层可以碰撞
  • 合理选择碰撞 vs 触发器以优化性能

练习题

  1. 创建两个球体,一个设定为 Trigger(作为拾取物品),玩家触碰后收集并销毁
  2. 实现一个伤害区域触发器:玩家进入后持续扣血
  3. 使用 Layer 让敌人物体之间不互相碰撞
  4. Physics.Raycast 实现射击检测,区分不同 Layer 的物体
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
Unity3D开发基础教程 系列
第 8/20 篇
分享: