UnityのOnCollisionEnter、OnTriggerEnter終止符


っしゃす。

なんか衝突でヒットする記事だいたい間違ってるので、自分のために検証して残しておきます。

検証内容・結果は最後に回します。暇な人は見てください。

結論

  • 衝突検知にはRigidBodyが必要だが、どちらかについてれば良い
    誰ですか、「両方RigidBodyが必要」とか言ってる人は。

  • 衝突検知の際には動いてるかに関わらず、両方のコールバックが呼び出される。

  • 2つともisTriggerがfalseの場合はOnCollisionEnter、それ以外はOnTriggerEnterが呼び出される。

  • なるべく動く方にRigidBodyを付ける(結果の表の注参照)

ところで、Colliderは衝突を検知するためのコンポーネントだが、RigidBodyは動くためのコンポーネントであるため、ステージの「動かない壁」などに用いるのはお勧めしない。ただし衝突検知にはRigidBodyが必要となる。

追記

衝突判定はColliderの空間にRigidBodyが含まれる場合に呼び出される。オブジェクトの速度が速すぎてCollider空間に入るフレームがない場合、呼び出されない。

例えばtフレームでcolliderの寸前まで来ていたオブジェクトがt+1フレームでColliderより奥に移動した場合、衝突は発生しない。

銃弾のような速さのオブジェクトの場合、1フレームの移動量分のRaycastで近似することでのみ衝突検知が可能で、自作した方が早い。

検証環境

Unity2020.3.1f1
RigidBodyのCollisionDetectionはContinuousSpeculative。

コード

ColliderTest.cs
using UnityEngine;

public class ColliderTest : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("OnTriggerEnterが起きたよ", gameObject);
    }
    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log("OnCollisionEnterが起きたよ", gameObject);
    }
}

シーン

この表の前提

  • ここでは二つのオブジェクトA、Bとする。
  • 動くオブジェクトは片方のみか、両方の場合がある。どちらも動かない場合衝突しない。
  • Colliderは当たり前だが、2つともついてるとする。
  • RigidBody列の〇はRididbodyあり、×はなし。
  • isTrigger列は〇はisTrigger=true、×はfalse。
  • コールバック列はOnTriggerEnterが呼び出される場合T、OnCollisionEnterが呼び出される場合C、いずれも呼び出されない場合×。

結果

動くオブジェクト RigidBody(A) RigidBody(B) isTrigger(A) isTrigger(B) コールバック(A) コールバック(B)
A × × × × × ×
A × × × × ×
A × × × × ×
A × × × ×
A × × × C C
A × × T T
A × × T T
A × T T
A × × × C△ C△
A × × T T
A × × T T
A × T T
A × × C C
A × T T
A × T T
A T T
A、B × × × × × ×
A、B × × × × ×
A、B × × × × ×
A、B × × × ×
A、B × × × C C
A、B × × T T
A、B × × T T
A、B × T T
A、B × × × C C
A、B × × T T
A、B × × T T
A、B × T T
A、B × × C C
A、B × T T
A、B × T T
A、B T T

注)結果のうち△は非常に稀にコールバックが確認された。使うべきではない。