【Unity】オブジェクトの発生場所が被らないようにするには?(Prefabは1つだけ)

2024年4月25日

Unityでオブジェクトをランダムな位置に生成し、既に他のオブジェクトが存在する位置には生成しないようにする方法について説明します。これを実現するための一般的な手法は、空いている位置を探すために物理的なチェック(Physics系のメソッドを使用する)を行うことです。以下にそのステップを示します。

3Dオブジェクトのケース

ステップ1: ランダムな位置を生成

まず、オブジェクトを生成したい範囲を定義します。例えば、x, y, z 座標が -10 から 10 の範囲内でランダムに位置を生成することができます。

ステップ2: 位置が空いているかどうかをチェック

生成したい位置に他のオブジェクトが存在しないかどうかをチェックします。これには Physics.CheckSpherePhysics.CheckBox などのメソッドが使用できます。これらのメソッドは、指定した範囲内にコライダーが存在するかどうかを確認します。

ステップ3: オブジェクトの生成

空いている位置が確認できたら、その位置にオブジェクトを生成します。もし位置が被っていた場合は、新しい位置をランダムに生成し、再度チェックを行います。

サンプルコード

以下のサンプルコードは、上記のプロセスを実装したものです。これを MonoBehaviour を継承したクラスに追加してください。

using UnityEngine;

public class RandomObjectSpawner : MonoBehaviour
{
    public GameObject prefab; // 生成するPrefabの参照
    public float range = 10.0f; // 生成するオブジェクトの位置を中心からどれだけ離して良いかの範囲(半径)
    public int maxAttempts = 10; // 生成位置が他のオブジェクトと重複しないように試行する最大回数

    void Start()
    {
        // コンポーネントがアクティブになったときにオブジェクトをランダムに生成する
        SpawnRandomObject();
    }

    void SpawnRandomObject()
    {
        int attempts = 0; // 現在の試行回数
        bool success = false; // オブジェクトの生成に成功したかどうかのフラグ

        while (!success && attempts < maxAttempts) // 成功するか最大試行回数に達するまでループ
        {
            Vector3 randomPosition = new Vector3(
                Random.Range(-range, range), // x座標をランダムに生成
                Random.Range(-range, range), // y座標をランダムに生成
                Random.Range(-range, range)  // z座標をランダムに生成
            );

            // 半径1の球を使って、生成位置に他のオブジェクトがないかどうかをチェック
            if (!Physics.CheckSphere(randomPosition, 1.0f))
            {
                // 他のオブジェクトと重複していない場合はPrefabをインスタンス化
                Instantiate(prefab, randomPosition, Quaternion.identity);
                success = true; // 成功フラグを立てる
            }
            else
            {
                attempts++; // 重複があれば試行回数を増やす
            }
        }

        if (!success)
        {
            // 最大試行回数に達しても適切な位置に生成できなかった場合はログに記録
            Debug.Log("指定回数内での配置に失敗しました。");
        }
    }
}

このコードでは、ランダムな位置を生成し、その位置に半径1の球を使って他のオブジェクトとの重複をチェックしています。重複がなければその位置にPrefabを生成します。最大試行回数に達するまでに適切な位置が見つからない場合、ログに失敗したことを記録します。この試行回数やチェックする球のサイズは、プロジェクトのニーズに応じて調整してください。

2Dオブジェクトのケース

2Dのオブジェクトをランダムな位置に生成し、すでに他のオブジェクトが存在する場所には生成しないようにするためには、2D専用の物理チェックメソッドを使用します。特に Physics2D.OverlapCircle を利用して、生成位置が空いているかどうかをチェックします。以下にそのための手順とサンプルコードを示します。

ステップ1: ランダムな位置を生成

生成したい範囲を決定します。2Dゲームでは通常、xとy座標を使用します。

ステップ2: 位置が空いているかどうかをチェック

Physics2D.OverlapCircle を使用して、指定した位置に他のコライダーがないかどうかをチェックします。この関数は指定した位置に円を描き、その円内に他のコライダーが重なっていないかを調べます。

ステップ3: オブジェクトの生成

空いている位置が確認できたら、その位置にオブジェクトを生成します。もし位置が被っていた場合は、新しい位置をランダムに生成し、再度チェックを行います。

サンプルコード

以下は、2Dのオブジェクトをランダムな位置に生成するためのスクリプトです。

using UnityEngine;

public class Random2DObjectSpawner : MonoBehaviour
{
    public GameObject prefab; // 生成するPrefabの参照を保持します
    public float range = 10.0f; // 生成範囲(x, y軸での最大値)
    public int maxAttempts = 10; // 最大試行回数(生成位置が重複しないようにする)

    void Start()
    {
        // ゲーム開始時にオブジェクトをランダムな位置に生成する
        SpawnRandomObject();
    }

    void SpawnRandomObject()
    {
        int attempts = 0; // 試行回数をカウント
        bool success = false; // 生成成功フラグ

        while (!success && attempts < maxAttempts) // 成功するか最大試行回数に達するまでループ
        {
            Vector2 randomPosition = new Vector2(
                Random.Range(-range, range), // x座標をランダムに決定
                Random.Range(-range, range)  // y座標をランダムに決定
            );

            // 半径1の円で他のオブジェクトとの重複をチェック
            // 重複がなければオブジェクトを生成
            if (Physics2D.OverlapCircle(randomPosition, 1.0f) == null)
            {
                Instantiate(prefab, randomPosition, Quaternion.identity); // オブジェクトを生成
                success = true; // 成功フラグを立てる
            }
            else
            {
                attempts++; // 重複があれば試行回数を増やす
            }
        }

        if (!success)
        {
            // 最大試行回数に達しても成功しない場合はログに記録
            Debug.Log("指定回数内での配置に失敗しました。");
        }
    }
}

このコードは、ランダムに選んだ位置に円を使って他の2Dコライダーとの重複をチェックしています。円の半径や試行回数は、具体的なプロジェクトの要件に応じて調整可能です。このスクリプトをUnityエディターでゲームオブジェクトにアタッチし、適切に設定することで使用できます。

Unity

Posted by hidepon