Unityで親子オブジェクトの当たり判定を管理する方法(初学者向け)

Unityで複数のオブジェクトを使ったゲームを作るとき、オブジェクト同士がぶつかる(当たり判定)をどうやって管理するかは重要なポイントです。この資料では、親オブジェクト子オブジェクトを使い、親が子の当たり判定を管理する方法をわかりやすく説明します。


1. 親子オブジェクトの基本

Unityでは、オブジェクト同士を親子関係にすることができます。例えば、車(親オブジェクト)とタイヤ(子オブジェクト)という関係を作ると、車が動くとタイヤも一緒に動きます。

今回の例では、親オブジェクトが子オブジェクトに別のオブジェクトがぶつかったことを知る方法を紹介します。


2. 子オブジェクトに当たり判定(Collider)を設定しよう

子オブジェクトが何かにぶつかったことを検知するには、Colliderというものを使います。

  1. 子オブジェクト1に BoxCollider を追加する。
  2. 子オブジェクト2にも BoxCollider を追加する。
  3. 子オブジェクトが動かない場合は、Rigidbodyコンポーネントを追加し、「isKinematic」にチェックを入れましょう。これで物理的には動かず、当たり判定だけができる状態になります。

3. 親オブジェクトのスクリプトで子オブジェクトの当たり判定を管理する

次に、親オブジェクトのスクリプトを作成して、子オブジェクトに何かがぶつかったことを受け取れるようにします。

親オブジェクトのスクリプト例

以下のスクリプトは、親オブジェクトに当たり判定があったことを子オブジェクトから通知する仕組みです。

using UnityEngine;

public class ParentCollisionHandler : MonoBehaviour
{
    // 子オブジェクトを参照する変数
    public GameObject childObject1;
    public GameObject childObject2;

    void Start()
    {
        // 子オブジェクトに通知スクリプトを追加し、当たり判定を親に伝える
        if (childObject1 != null)
        {
            CollisionNotifier notifier1 = childObject1.AddComponent<CollisionNotifier>();
            notifier1.OnCollisionDetected += HandleCollision;
        }

        if (childObject2 != null)
        {
            CollisionNotifier notifier2 = childObject2.AddComponent<CollisionNotifier>();
            notifier2.OnCollisionDetected += HandleCollision;
        }
    }

    // 子オブジェクトで当たり判定が発生したときの処理
    private void HandleCollision(GameObject collidedObject, GameObject sourceObject)
    {
        Debug.Log(sourceObject.name + " に " + collidedObject.name + " が衝突しました");
    }
}

子オブジェクト用スクリプト

子オブジェクトが何かにぶつかったときに親オブジェクトに知らせる役割を持つスクリプトを作成します。

using UnityEngine;

public class CollisionNotifier : MonoBehaviour
{
    // イベントの作成
    public delegate void CollisionDetectedHandler(GameObject collidedObject, GameObject sourceObject);
    public event CollisionDetectedHandler OnCollisionDetected;

    // 何かがぶつかったときの処理
    private void OnCollisionEnter(Collision collision)
    {
        if (OnCollisionDetected != null)
        {
            OnCollisionDetected.Invoke(collision.gameObject, this.gameObject);
        }
    }

    // トリガー用の当たり判定
    private void OnTriggerEnter(Collider other)
    {
        if (OnCollisionDetected != null)
        {
            OnCollisionDetected.Invoke(other.gameObject, this.gameObject);
        }
    }
}

public delegate void CollisionDetectedHandler(GameObject collidedObject, GameObject sourceObject);および public event CollisionDetectedHandler OnCollisionDetected; は、C#で独自のデリゲート型とイベントを定義して、オブジェクト同士の当たり判定を処理する仕組みを作るためのコードです。

1. デリゲート (delegate) とは

デリゲートは、C#でメソッドを参照するための型を定義するものです。簡単に言えば、「メソッドへの参照」を保持できる型です。
delegate void CollisionDetectedHandler(GameObject collidedObject, GameObject sourceObject); では、次の内容が含まれています:

  • void: メソッドが何も値を返さない(戻り値なし)。
  • GameObject collidedObject: メソッドが呼び出されるときに、衝突したオブジェクトの情報(GameObject型)を受け取ります。
  • GameObject sourceObject: 衝突元のオブジェクト(GameObject型)を受け取ります。

このデリゲート型は、当たり判定に関連するメソッドがどういった引数(GameObject型のオブジェクト2つ)を受け取り、何も値を返さないという構造を定義しています。

例:

このデリゲートを使ってメソッドを登録することができます。例えば、次のようなメソッドを定義し、デリゲート型として扱えます。

void OnCollision(GameObject collidedObject, GameObject sourceObject)
{
    Debug.Log(sourceObject.name + " に " + collidedObject.name + " が衝突しました");
}

この OnCollision メソッドは、CollisionDetectedHandler デリゲート型と互換性があり、引数に GameObjectを2つ取り、戻り値を返しません。


2. イベント (event) とは

イベントは、ある条件が発生したときに通知する仕組みです。イベントはデリゲートと組み合わせて使われます。event キーワードを使うことで、特定のデリゲート型を持つイベントを定義します。

public event CollisionDetectedHandler OnCollisionDetected; では、次のことを実現しています:

  • OnCollisionDetected というイベントを宣言。
  • OnCollisionDetected イベントは、CollisionDetectedHandler デリゲート型のメソッドを持つことができ、外部のオブジェクトがそのイベントにメソッドを登録できる。
  • イベントが発生すると、登録されたメソッドが順番に呼び出されます。

3. 実際の使用方法

イベントの発火(通知)

OnCollisionDetected イベントは、通常、衝突が発生したときに発火(通知)されます。この例では、OnCollisionEnter や OnTriggerEnter で衝突が検知されたときに、登録されたメソッドを呼び出す形になります。

private void OnCollisionEnter(Collision collision)
{
    // イベントが誰かに登録されている場合、そのメソッドを呼び出す
    if (OnCollisionDetected != null)
    {
        OnCollisionDetected.Invoke(collision.gameObject, this.gameObject);
    }
}

イベントの登録

別のオブジェクトから、このイベントに対してメソッドを登録できます。例えば、親オブジェクトでこのイベントに対応するメソッドを登録します。

void Start()
{
    // 子オブジェクトのイベントにメソッドを登録
    childObject.GetComponent<CollisionNotifier>().OnCollisionDetected += OnCollision;
}

// 子オブジェクトの衝突を処理するメソッド
void OnCollision(GameObject collidedObject, GameObject sourceObject)
{
    Debug.Log(sourceObject.name + " に " + collidedObject.name + " が衝突しました");
}

4. まとめ

  • デリゲート (delegate) はメソッドのシグネチャ(引数や戻り値の型)を定義するものです。この場合、GameObject型の2つの引数を持ち、voidを返すメソッドを参照するために使用されます。
  • イベント (event) は、特定のタイミング(この場合は衝突)で通知を行い、複数のメソッドを登録して実行するための仕組みです。
  • OnCollisionDetected イベントを使うことで、他のオブジェクトが衝突時に何かの処理を行うようにすることができます。

この仕組みを使うことで、子オブジェクトが衝突した際に、親オブジェクトでその処理を一元的に行うことができます。

using UnityEngine;
using System;

public class CollisionNotifier : MonoBehaviour
{
    // eventを使った当たり判定のデリゲート
    public event Func<GameObject, GameObject, bool> OnCollisionDetected;

    // OnCollisionEnterでの衝突検知
    private void OnCollisionEnter(Collision collision)
    {
        if (OnCollisionDetected != null)
        {
            OnCollisionDetected.Invoke(collision.gameObject, this.gameObject);
        }
    }

    // OnTriggerEnterでのトリガー検知
    private void OnTriggerEnter(Collider other)
    {
        if (OnCollisionDetected != null)
        {
            OnCollisionDetected.Invoke(other.gameObject, this.gameObject);
        }
    }
}


4. 設定手順

  1. 親オブジェクトParentCollisionHandlerスクリプトをアタッチします。
  2. インスペクタで、childObject1 と childObject2 に子オブジェクトをドラッグして設定します。
  3. 各子オブジェクトにBoxColliderRigidbodyを追加します。

5. どうしてこうするの?

  • 親オブジェクトがまとめて管理できる: 子オブジェクトの当たり判定がいくつもある場合でも、親がそれらをまとめて管理できるので、スクリプトがシンプルになります。
  • イベントを使うCollisionNotifier を使って、子オブジェクトが当たり判定を通知し、それを親が受け取ります。これにより、効率的に衝突処理を実現できます。

まとめ

この方法を使うことで、親オブジェクトで複数の子オブジェクトの当たり判定を簡単に管理することができます。ゲーム開発では、キャラクターやアイテムなどを親子関係にすることが多く、親オブジェクトが子の動作を管理することで、よりスムーズな開発が可能になります。

最初は複雑に見えるかもしれませんが、親子オブジェクトの使い方に慣れてくると、シーンの整理や処理の管理が簡単になります。ぜひこの方法を試してみてください!

Unity

Posted by hidepon