Unity 物理系统之刚体、碰撞体、触发器

4,542 阅读5分钟

主要参照 Unity 官方文档的以下几篇文章,重新进行了整理。 docs.unity3d.com/Manual/Phys… docs.unity3d.com/Manual/clas… docs.unity3d.com/Manual/clas…

Unity 物理系统中,刚体用于接受各种力的作用,具有速度,来控制物体的移动。
碰撞体用于各个物体之间的交互、碰撞,从而影响物体的移动。
刚体通常和碰撞体一起使用,模拟现实中的世界。

刚体

  • 会受到重力等力的作用,而产生移动,但是不会发生形变。
  • 加了刚体的物体,不应该通过 Transform 来 move、rotate、scale。应该通过 Rigidbody.MovePosition、Rigidbody.MoveRotation、Rigidbody2D.MovePosition、Rigidbody2D.MoveRotation 来移动。

刚体类型 BodyType

刚体类型是刚体的一个重要属性。

  • 决定移动的行为(位置、翻转)
  • (如果有碰撞体组件的话)决定碰撞交互的方式
  • 改变 BodyType 是一个很消耗性能的操作

有如下 3 种类型。

动态 Dynamic

  • 默认类型
  • 受重力和附加力的影响,进而改变速度。
  • 性能消耗最高的类型。
  • 可通过 MovePosition、MoveRotation 来移动。
  • 可通过 velocity 来改变速度。
  • 用来模拟移动的物体。

运动学 Kinematic

  • 不受力的影响。
  • 性能消耗比 Dynamic 少,比 Static 多。
  • 可通过 MovePosition MoveRotation 来移动。
  • 可通过 velocity 来改变速度。
  • 用来模拟大多数时候不动的物体,极少数时候需要移动。比如门。

静态 Static

  • 不受力的影响,物理系统不会对该物体进行计算。
  • 性能消耗最低的类型。
  • 不可通过 MovePosition MoveRotation 来移动。
  • 不可通过 velocity 来改变速度。
  • 用来模拟从不移动的物体。

在 Physics2D 中设置刚体类型

Physics2D 中 Rigidbody2D 组件有 BodyType 属性,没有 IsKinematic 属性。

  • Dynamic:添加 Rigidbody2D,设置 BodyType 为 Dynamic。
  • Kinematic:添加 Rigidbody2D,设置 BodyType 为 Kinematic。
  • Static:
    • 添加 Rigidbody2D,设置 BodyType 为 Static。
    • 不添加 Rigidbody2D 组件,但是有 Collider2D 组件。相当于有一个隐藏的 Static Rigidbody2D。
      • 比较简单,不用另外添加刚体,并设置类型。
      • 效率不如明确添加刚体的方式。

在 Physics3D 中设置刚体类型

Physics3D 中 Rigidbody 组件有 IsKinematic 属性,没有 BodyType 属性。

  • Dynamic:添加 Rigidbody,不勾选 IsKinematic。
  • Kinematic:添加 Rigidbody,勾选 IsKinematic。
  • Static:不添加 Rigidbody,但是有 Collider 组件。

碰撞体

  • 会发生碰撞,并因为碰撞而移动。
  • 定义 GameObject 的形状以用于碰撞检测,会触发相应的碰撞体回调函数。
  • 碰撞体是不可见的,碰撞体的形状不用和实际的网格(mesh)形状一致。

与 3 种类型的刚体对应,碰撞体根据添加的刚体类型,也有 3 种类型的碰撞体。

静止刚体的碰撞体 Static Rigidbody Collider

  • 有碰撞体
    • 没有刚体
    • 或者刚体类型为 Static。
  • 不受力和碰撞的影响
  • 可以和其他碰撞体发生碰撞,但是自己不会移动。物理系统会做优化。
  • 游戏过程中尽量避免 enable、disable、move、scale,否则会有大的性能消耗,甚至出现错误。
  • 如果大部分时候是静止的,但是某些情况下需要移动,那么应该使用 Kinematic Rigidbody Collider。

动态刚体的碰撞体 Dynamic Rigidbody Collider

  • 有碰撞体,有刚体,刚体类型是 Dynamic。
  • 最常用的,会受到力和碰撞的影响。

运动学刚体的碰撞体 Kinematic Rigidbody Collider

  • 有碰撞体,有刚体,刚体类型是 Kinematic。
  • 可以通过 Transform 来移动位置
  • 不受力和碰撞的影响
  • 偶尔会被 move、enable、disable,大多数时候和 Static Collider 一致。

触发器

  • 碰撞体勾选 isTrigger 后成为触发器
  • 与碰撞体的主要区别
    • 其他碰撞体可以穿过该(触发器)碰撞体,不会受到阻挡。
    • 穿过该碰撞体时,会触发相应的触发器回调函数。
  • 与 3 种类型的碰撞体对应,勾选 isTrigger 后对应 3 种类型的触发器。

碰撞体碰撞规则

  • Dynamic 刚体的碰撞体和其他碰撞体,会有回调。
Collision detection occurs and messages are sent upon collision
Static Rigidbody Collider Dynamic Rigidbody Collider Kinematic Rigidbody Collider Static Rigidbody Trigger Collider Dynamic Rigidbody Trigger Collider Kinematic Rigidbody Trigger Collider
Static Rigidbody Collider Y
Dynamic Rigidbody Collider Y Y Y
Kinematic Rigidbody Collider Y
Static Rigidbody Trigger Collider
Dynamic Rigidbody Trigger Collider
Kinematic Rigidbody Trigger Collider

碰撞体相关回调函数

  • MonoBehaviour
    • OnCollisionEnter2D(Collider2D)
    • OnCollisionStay2D(Collider2D)
    • OnCollisionExit2D(Collider2D)
    • OnCollisionEnter(Collider)
    • OnCollisionStay(Collider)
    • OnCollisionExit(Collider)

触发器触发规则

  • Dynamic、Kinematic 刚体的触发器,和任何碰撞体、触发器都会有回调。
  • Static 刚体的触发器碰撞体,只能和 Dynamic、Kinematic 刚体的碰撞体、触发器有回调。
Trigger messages are sent upon collision
Static Rigidbody Collider Dynamic Rigidbody Collider Kinematic Rigidbody Collider Static Rigidbody Trigger Collider Dynamic Rigidbody Trigger Collider Kinematic Rigidbody Trigger Collider
Static Rigidbody Collider Y Y
Dynamic Rigidbody Collider Y Y Y
Kinematic Rigidbody Collider Y Y Y
Static Rigidbody Trigger Collider Y Y Y Y
DynamicRigidbody Trigger Collider Y Y Y Y Y Y
Kinematic Rigidbody Trigger Collider Y Y Y Y Y Y

触发器相关回调函数

  • MonoBehaviour
    • OnTriggerEnter2D(Collider2D)
    • OnTriggerStay2D(Collider2D)
    • OnTriggerExit2D(Collider2D)
    • OnTriggerEnter(Collider)
    • OnTriggerStay(Collider)
    • OnTriggerExit(Collider)

其他细节

休眠

  • 当刚体移动速度小于一个特定值后,就会进入休眠状态(Sleeping)。以降低性能消耗。
  • 休眠状态下,
    • 不会参与物理系统的计算。
    • 发生碰撞或者受到力的作用,会重新参与物理系统的计算。
    • 如果有静态碰撞体通过 Transform 来移动,并接触/离开一个 Sleeping 的刚体,该刚体不会重新参与计算,可能会悬浮在空中,发生不可预知的错误。此时需要通过 WakeUp 来唤醒。理论上不应该移动静态碰撞体,也就不会出现这种情况。