【Unity】当たり判定を実装する

はじめに

今回はゲーム実装では欠かせない当たり判定をUnityで実装していきたいと思います。

GameObjectにColliderを設定する

当たり判定を実装する場合はOnCollisionもしくはOnTriggerというメソッドを実装します。

公式ドキュメントにあるようにOnCollisionもしくはOnTriggerを実装するにはRigidbodyとColliderのコンポーネントが必要となります。

RigidbodyとColliderは、触れる側、触れられる側どちらでも実装する必要があります。

この collider/rigidbody は他の collider/rigidbody に触れたときに OnCollisionEnter は呼び出されます。

Collider-OnCollisionEnter(Collision) - Unity スクリプトリファレンスより引用

Rigidbodyコンポーネントとは

Rigidbodyコンポーネントは物理演算をゲームオブジェクトに対して適用するためのコンポーネントです。

公式ドキュメントには以下のような説明もあります。

Rigidbody はオブジェクトに力を適用し、物理的に現実的な方法でそれをコントロールするためのスクリプト API も有しています。例えば、ある自動車の挙動は車輪によって加えられる力という面から指定することができます。この情報に基づけば、物理エンジンは車の挙動のその他ほとんどの側面を扱うことができるので、現実的に加速したり、衝突に対して正確に応答します。

UnityEngine.Rigidbody - Unity スクリプトリファレンスより引用

Colliderコンポーネント

Colliderには主に以下の3つの種類があります。

Collider 特徴
BoxCollider 立方体型のCollider
SphereCollider 球体型のCollider
CapsuleCollider カプセル型のCollider

言葉だけだとわかりづらいのでシーン上に配置して形を確認してみます。

シーン上にCubeを配置し、そこにColliderをアタッチしてみます。

BoxCollider

BoxColliderは立方体なので、Cubeと形は同じです。

※わかりやすいようにColliderの大きさは大きめに設定しています。

f:id:dasuko:20200915223235p:plain

SphereCollider

SphereColliderも見ていただければわかるように球体です。

※わかりやすいようにColliderの大きさは大きめに設定しています。

f:id:dasuko:20200915223435p:plain

CapsuleCollider

CapsuleColliderは公式ドキュメントには以下のように説明があります。

カプセルは両端に半球を持つシリンダーです。

UnityEngine.CapsuleCollider - Unity スクリプトリファレンスより引用

  

画像にあるように両端に半球をもつシリンダーであることが確認できました。

※わかりやすいようにColliderの大きさは大きめに設定しています。

f:id:dasuko:20200915223721p:plain

GameObjectにコンポーネントを追加する

コンポーネントを追加する場合はGameObjectを選択した状態でInspectorの一番下にある"Add Component"をクリックします。

f:id:dasuko:20200915224128p:plain

追加したいコンポーネント名を入力して選択すれば、コンポーネントがGameObjectにアタッチされます。

まずはColliderコンポーネントを追加します。

f:id:dasuko:20200915224312p:plain

次にRigidbodyコンポーネントを追加します。

f:id:dasuko:20200915224427p:plain

スクリプトを書く

Assets>Create>C# Scriptで新しいスクリプトを追加します。

スクリプトの追加方法はいくつかりますが、どれでも大丈夫です。

当たり判定を取得するためのメソッド

衝突が起こったときに呼ばれるメソッドはOnCollisionというメソッドとOnTriggerというメソッドがあります。

OnCollision**メソッドは衝突が発生する(当たった時に跳ね返る)場合に使います。

OnTrigger**メソッドは衝突が発生せず、オブジェクトを擦り抜けさせたい場合に使います。

擦り抜けさせたい場合はColliderコンポーネントのisTriggerにチェックを入れます。 (跳ね返らせたい場合はチェックを外します。)

f:id:dasuko:20200915234819p:plain

またRigidbodyコンポーネントのisKinematicにチェックを入れることにより物理演算を無効にすることもできます。

f:id:dasuko:20200915235125p:plain

また、これらのメソッドは引数も異なります。

OnCollision

OnCollision**を実装するメリットとしては引数がCollisionオブジェクトのため、

接触点や衝突速度といった情報を含むため、余計な計算が不要となります。

OnCollision**メソッドには以下のようなメソッドがあります。

メソッド名 呼ばれるタイミング
OnCollisionEnter ColliderもしくはRigidbodyが他のColliderもしくはRigidbodyと触れた時に呼ばれます
OnCollisionStay ColliderもしくはRigidbodyが他のColliderもしくはRigidbodyと接触している間1フレームに1回呼ばれます
OnCollisionExit ColliderもしくはRigidbodyが他のColliderもしくはRigidbodyと触れるのが終わるタイミングで呼ばれます

OnTrigger

OnTrigger**メソッドの引数はColliderオブジェクトです。

OnTrigger**メソッドには以下のようなメソッドがあります。

メソッド名 呼ばれるタイミング
OnTriggerEnter ColliderもしくはRigidbodyが他のColliderもしくはRigidbodyと触れた時に呼ばれます
OnTriggerStay ColliderもしくはRigidbodyが他のColliderもしくはRigidbodyと接触している間1フレームに1回呼ばれます
OnTriggerExit ColliderもしくはRigidbodyが他のColliderもしくはRigidbodyと触れるのが終わるタイミングで呼ばれます

実装

以下のようにシーン上に二つのCubeを配置して、Rigidbodyコンポーネントをアタッチしました。

※Colliderコンポーネントは既に追加されています。

f:id:dasuko:20200916000218p:plain

そして、片方のCubeに以下のスクリプトをアタッチしました。

using UnityEngine;

public class CollisionTest : MonoBehaviour
{
    Rigidbody rigidbody;

    private void Start()
    {
        rigidbody = GetComponent<Rigidbody>();
        var velocity = rigidbody.velocity;
        velocity.z = 20;
        rigidbody.velocity = velocity;
    }

    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log("OnCollisionEnter");

        var velocity = rigidbody.velocity;
        velocity.z = 0;
        rigidbody.velocity = velocity;
    }

    private void OnCollisionStay(Collision collision)
    {
        Debug.Log("OnCollisionStay");
    }

    private void OnCollisionExit(Collision collision)
    {
        Debug.Log("OnCollisionExit");
    }
}

Startでz方向の速度を20に設定し、OnCollisionEnterで衝突したら、速度を0にしています。

OnCollision**を使っており、isTriggerはfalseなのでぶつかった方のCubeはぶつかった衝撃でそのまま移動を続けるため、

OnCollisionEnter, OnCollisionStay, OnCollisionExitは1回ずつ呼ばれるはずです。

では、実行してみます。

f:id:dasuko:20200916000542p:plain

想定通り、各メソッドが1回ずつ呼ばれました!

まとめ

当たり判定はゲーム開発では基本中の基本なので

調べないでも実装できるようになりたいですね。

OnTriggerでもonCollisionでも引数から衝突したGameObjectを取得することができるので、

そこからダメージを与えるとか、エフェクトを発生させるといった処理が可能です。

今回の実装例にあるOnCollision**では以下のようにCollisionからGameObjectを取得できます。

        var obj = collision.gameObject;

参考

Unity スクリプトリファレンス