汎用的な当たり判定スクリプト(OnTriggerStay編)

広告

当たり判定には、OnTrigger系のイベントとOnCollision系のイベントがあります。 必要なスクリプトに都度記述してもいいのですが、オブジェクトにアタッチすることでこのイベントをさらに外部へ通知できる汎用的な仕組みにできます。 本記事では OnTriggerStay を例に、UnityEvent を使った汎用当たり判定スクリプトを紹介します。


汎用スクリプトの仕組み

コード内には、具体的にどのメソッドを実行するかは記述せずにインスペクタで登録するようにします。

イメージ

 ▲ CollisionDetector をアタッチしたオブジェクトのインスペクタ。「On Trigger Stay Event」欄に、当たり判定時に呼び出したいメソッドを登録します。


当たり判定を汎用的に使えるコード

[RequireComponent(typeof(Collider))] について

このスクリプトは Collider がアタッチされているオブジェクトでのみ動作します。 [RequireComponent]を付けることで、Collider なしにアタッチしようとした際に Unity がエラーを出して気づかせてくれます。実用時は必ず付けることを推奨します。

[RequireComponent(typeof(Collider))]
public class CollisionDetector : MonoBehaviour
{
    // [SerializeField] により private フィールドをインスペクタに公開しています
    // public にしないのは、外部スクリプトから直接変更されるのを防ぐためです
    [SerializeField]
    private UnityEvent<Collider> onTriggerStayEvent;

    // Is Trigger が ON で他の Collider と重なっているときは
    // このメソッドが常にコールされる
    private void OnTriggerStay(Collider other)
    {
        // Unity のライフサイクルメソッド OnTriggerStay(大文字O)と
        // フィールド名 onTriggerStayEvent を区別してください
        onTriggerStayEvent.Invoke(other);
    }
}

補足:なぜ継承が不要になったか

Unity 2020 以前は UnityEvent<T> が抽象クラスとして扱われ、[Serializable] な派生クラスを自分で定義しないとインスペクタに表示できませんでした。 Unity 2020 以降はジェネリック型でも直接シリアライズできるようになったため、継承クラスなしで UnityEvent<Collider> をそのまま使えます。 旧コードは後述の「参考」に残しています。


インスペクタで実行してほしいメソッドを登録

コライダーがアタッチされたオブジェクトにスクリプトをアタッチします。 イベントの登録箇所に、当たり判定検出時に実行したいメソッドを登録します。 他のオブジェクトにアタッチされているメソッドでも構いません。

▲ 登録例:別オブジェクトにアタッチされたスクリプトのメソッドでも指定可能です。


参考

Unity の UnityEvent 仕様変更前のコード

UnityEvent<T> が抽象クラスだった時代は、一旦継承させて使う必要がありました。

参考:UnityEventのコールバック関数に、動的に引数を渡す – Unityな日々(Unity Geek)

using System;
using UnityEngine;
using UnityEngine.Events;

[RequireComponent(typeof(Collider))]
public class CollisionDetector : MonoBehaviour
{
    [SerializeField] private TriggerEvent onTriggerStayEvent = new TriggerEvent();

    /// <summary>
    /// Is Trigger が ON で他の Collider と重なっているときは、このメソッドが常にコールされる
    /// </summary>
    private void OnTriggerStay(Collider other)
    {
        onTriggerStayEvent.Invoke(other);
    }

    // UnityEvent を継承したクラスに [Serializable] 属性を付与することで
    // インスペクタウインドウ上に表示できるようになる
    [Serializable]
    public class TriggerEvent : UnityEvent<Collider>
    {
    }
}
訪問数 6 回, 今日の訪問数 6回

広告

Unity

Posted by hidepon