物理碰撞检测与触发器检测

分类 Collider 类型 API 类型 / 返回值 说明
形状 Collider BoxCollider center Vector3 碰撞盒中心点(局部坐标)
size Vector3 碰撞盒尺寸(局部坐标)
SphereCollider center Vector3 球心(局部坐标)
radius float 球半径
CapsuleCollider center Vector3 胶囊体中心(局部坐标)
radius float 半径
height float 高度
direction int 方向轴(0=X,1=Y,2=Z)
MeshCollider sharedMesh Mesh 使用的网格资源
convex bool 是否为凸体(决定是否可与 Rigidbody 配合)
Collider 通用属性 所有 Collider enabled bool 是否启用该 Collider
isTrigger bool 是否为触发器(不产生物理碰撞)
attachedRigidbody Rigidbody 绑定在同一物体上的 Rigidbody
material PhysicMaterial 碰撞材质(摩擦、弹性)
contactOffset float 碰撞检测的容差偏移
bounds Bounds Collider 的世界空间包围盒
Collider 查询方法 所有 Collider ClosestPoint(Vector3 position) Vector3 返回 Collider 上距离指定点最近的位置
Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance) bool 射线是否与 Collider 相交
OverlapPoint(Vector3 point) bool 判断某点是否在 Collider 内部
Bounds 属性 Bounds center Vector3 包围盒中心点(世界坐标)
size Vector3 包围盒整体尺寸
extents Vector3 半尺寸(size / 2)
min Vector3 最小点(左下后)
max Vector3 最大点(右上前)
Bounds 方法 Bounds Contains(Vector3 point) bool 判断点是否在包围盒内
Intersects(Bounds bounds) bool 判断两个包围盒是否相交
IntersectRay(Ray ray) bool 判断射线是否与包围盒相交
SqrDistance(Vector3 point) float 点到包围盒的平方距离
Expand(float amount) void 按标量扩展包围盒
Expand(Vector3 amount) void 按向量扩展包围盒

1. 物理碰撞的基本条件

要产生碰撞或触发检测,必须满足以下条件:

✔ 必要条件

  1. 至少一个物体拥有 Rigidbody(刚体)
  2. 两个物体都必须有 Collider(碰撞器)

2. Rigidbody 常用参数

2.1 基础属性

  • Mass(质量):质量越大惯性越大
  • Drag(空气阻力):影响移动阻力
  • Angular Drag(角阻力):影响旋转阻力
  • Use Gravity:是否受重力影响

2.2 Is Kinematic

  • 启用后刚体不受物理引擎控制
  • 可用脚本(Transform)直接移动
    常用于:
  • 移动平台
  • 配合 Joint 的受控物体

2.3 Interpolate(插值)

用于平滑刚体移动:

  • None:不插值
  • Interpolate:基于上一帧
  • Extrapolate:基于下一帧预测

2.4 Collision Detection(碰撞检测模式)

用于防止快速物体穿透:

模式 说明
Discrete 默认模式,一般物体使用
Continuous 对快速物体检测静态物体
Continuous Dynamic 高成本,适用于高速物体
Continuous Speculative 成本低,推测性判断

2.5 Constraints(约束)

  • Freeze Position:锁定位置移动
  • Freeze Rotation:锁定旋转

3. Collider(碰撞器)

3.1 常用碰撞器

  • BoxCollider
  • SphereCollider
  • CapsuleCollider
  • MeshCollider(需设置 Convex 才可用于物理)

3.2 MeshCollider 使用规则

  • 若用于物理碰撞,必须勾选 Convex
  • 异形物体通常使用多个 Primitive Collider 组合

4. 物理材质(Physic Material)

4.1 基本属性

  • Dynamic Friction(动摩擦):移动时的摩擦
  • Static Friction(静摩擦):静止时的摩擦
  • Bounciness(弹性):反弹能力

4.2 摩擦与弹性组合方式(Combine)

  • Average:平均
  • Minimum:最小
  • Maximum:最大
  • Multiply:相乘

5. 碰撞检测函数(Collision)

必须满足:

✔ 双方 Collider
✔ 至少一方 Rigidbody
✔ Collider 未勾选 Trigger

//物体首次碰撞发生接触 调用一次:
private void OnCollisionEnter(Collision collision)
{
  if(collision.gameObject.CompareTag("Player")
  {
    print($"和{collision.gameObject.name}碰撞了";
    //获取Player物体上挂载的脚本
    T t = collision.GetComponent<T>();
  }
}

//物体碰撞接触后 每帧调用:
private void OnCollisionStay(Collision collision) {}

//物体分离碰撞接触时 调用一次:
private void OnCollisionExit(Collision collision) {}

6. 触发器检测函数(Trigger)

必须满足:

✔ 双方 Collider
✔ 至少一方 Rigidbody
✔ 一方 Collider 勾选 Trigger

//首次进入触发器范围 调用一次:
private void OnTriggerEnter(Collider other)
{
  if(other.gameObject.CompareTag("Player")
  {
    print($"和{other.gameObject.name}碰撞了";
    //获取Player物体上挂载的脚本
    T t = other.GetComponent<T>();
  }}
}

//进入触发器范围后 每帧调用
private void OnTriggerStay(Collider other) {}

//离开触发器范围时 调用一次
private void OnTriggerExit(Collider other) {}

7. 重要规则(非常关键)

✔(1)异形物体检测规则

1.父物体挂载刚体组件,父物体有 Rigidbody 后,物理引擎会把这个 Rigidbody 当作整个父子层级的刚体
2.子物体挂载碰撞器,并且设置为想要触发的标签,子物体可以挂载多个相同或不同碰撞器进行组合,使得符合子物体形状
3.进行if(other.gameObject.CompareTag("Player"))检测,检测的结果 other 是子物体
4.逻辑脚本挂载父物体还是子物体由游戏实际情况决定
可以挂载在父物体上,将脚本设置为单例,直接通过单例获取脚本,解决other获取的是子物体而不是父物体
可以挂载在子物体上,通过other.GetComponent获取脚本,不过要注意子物体是否是预制体,在多个场景下复用时,脚本的Update是否符合想要的效果


8. Trigger触发器检测和范围检测的区别

特性 范围检测 (Overlap/Check) 触发检测 (Trigger)
触发方式 玩家或逻辑主动调用,每帧检测 物理引擎自动调用,事件驱动
依赖组件 不依赖 Rigidbody 必须有 Rigidbody(父物体或自身)
灵活性 高,可自定义形状、范围、条件 中,受物理组件限制
典型应用 按键后技能释放、按键后玩家主动范围交互(按空格进入传送门) 自动拾取道具、自动触发传送门
是否需要按键触发 非常建议使用,如果不使用就和自动触发一样,不如使用Trigger 不需要,进入触发器就自动触发
控制权 由玩家完全控制 由物理事件控制

9. Collider.bounds

类型:Bounds(Unity 提供的结构体)
含义:碰撞器在 世界坐标系 下的轴对齐包围盒 (AABB)。
特点:
始终与世界坐标轴对齐,即使 Collider 本身旋转了,bounds 仍然是一个矩形盒子。
常用于快速范围检测(点是否在碰撞体范围内)。
常用属性:
bounds.center → 包围盒中心点(世界坐标)
bounds.size → 包围盒整体尺寸(宽、高、深)
bounds.min → 包围盒最小点(左下后角)
bounds.max → 包围盒最大点(右上前角)

常用方法:
bounds.Contains(Vector3 point) → 判断某个点是否在包围盒范围内。

posted @ 2025-12-04 19:04  高山仰止666  阅读(17)  评论(0)    收藏  举报