はじめに
例えばゲームの敵キャラなどをたくさん配置したいことがあると思います.ランダムに配置できるようになると,毎回状況が変わるのでより魅力的なゲームを提供できます.今回はUnityでスクリプトを使い、ランダムな位置にオブジェクトを生成する方法を解説します.
この記事を読むと指定した個数のオブジェクトをランダムに配置することができるようになります.
ランダムな位置にオブジェクトを生成する
ランダム位置への生成スクリプトの作製
生成したいオブジェクトのプレハブを用意してください.プレハブについて詳しく知りたい方は以下の記事をチェック!

今回用意したスクリプトは以下の通りです.
public class generateRandomWithCube : MonoBehaviour
{
public GameObject prefab;
public int num;
public float min;
public float max;
void Start()
{
for (int i = 0; i < num; i++)
{
Vector3 pos = new Vector3(
Random.Range(min, max),
Random.Range(min, max),
Random.Range(min, max)
);
Instantiate(prefab, pos, Quaternion.identity);
}
}
}
空のGameObjectにスクリプトをアタッチし,生成したいオブジェクトのプレハブをセットしてください.細かい手順は以下の記事で解説しています.
再生ボタンをクリックすると,ランダムな位置に指定した数のオブジェクトが生成されます.停止と再生を繰り返し,確認してみましょう!
num欄に個数を入力すれば指定の個数分生成できます.
ランダム位置への生成スクリプトの解説
それではスクリプトを見ていきましょう.
今回はRandom.Range関数でランダムな値を取得しています.Randome.Range(a, b)
とすることでa ~ bの範囲内の値を返します.
この範囲に関しては次章で詳しく解説します.
取得したランダムな座標を指定してInstantiateでオブジェクトを作成します.
for文を用いてこれらの処理を生成したいオブジェクトの個数分繰り返しています.
生成する位置を制限する方法
例えば範囲制限のない完全にランダムな位置に生成すると,意図しない悪影響を及ぼす可能性があります.他のオブジェクトの振る舞いに影響を与えたり,カメラの視界外で生成してしまったりします.
ここではランダム生成の範囲を制限する方法を二つ紹介します.
立方体の範囲内に配置

先のスクリプトで利用した方法です.以下のように実装することができます.
public class generateRandomWithCube : MonoBehaviour
{
public GameObject prefab;
public int num;
public float min;
public float max;
void Start()
{
for (int i = 0; i < num; i++)
{
float x = Random.Range(min, max);
float y = Random.Range(min, max);
float z = Random.Range(min, max);
Vector3 pos = new Vector3(x, y, z);
Instantiate(prefab, pos, Quaternion.identity);
}
}
}
x, y, zのどれかを定数にすれば平面内や直線内の制限も実装可能です.それぞれに変数を用意すれば立方体に限らず様々な多面体範囲に制限をすることができるでしょう.
球状の範囲内に設置

ある中心から球半径rの球の内側に生成範囲を制限します.以下のように実装することができます.
public class generateRandomWithSphere : MonoBehaviour
{
public GameObject prefab;
public int num;
public float radius;
private Vector3 originPos = new Vector3(1, 1, 1);
void Start()
{
for (int i = 0; i < num; i++)
{
Vector3 pos = Random.insideUnitSphere * radius;
Instantiate(prefab, originPos + pos, Quaternion.identity);
}
}
}
Random.insideUnitSphereを利用することで,半径1の球内の座標を取得できます.これを望む半径まで拡大することで,半径r内の座標をランダムに取得しました.
球の中心をoriginPosに設定し,取得したランダム座標と足すことで移動しています.
特定の範囲を除く
少し荒業ではありますが,特定の範囲を除くこともできます.
まずは通常通りランダムな座標を取得します.if文を用いて取得した座標が除きたい特定の範囲内かどうかを判定します.範囲外であればその位置にオブジェクトを生成します.範囲内であれば,範囲外の座標を取得できるまでwhile分で取得と判定を繰り返します.
下のスクリプトでは例としてy座標が0より大であり,xとzがそれぞれ-1 ~ 1の範囲を除いています.
public class generateRandomWithoutArea : MonoBehaviour
{
public GameObject prefab;
public int num;
public float min;
public float max;
void Start()
{
for (int i = 0; i < num; i++)
{
while (true)
{
float x = Random.Range(min, max);
float y = Random.Range(min, max);
float z = Random.Range(min, max);
if(y > 0)
{
if((Mathf.Abs(x) > 1) && (Mathf.Abs(x) > 1))
{
Vector3 pos = new Vector3(x, y, z);
Instantiate(prefab, pos, Quaternion.identity);
break;
}
}
}
}
}
}
例えば舞台上の建物にかぶせないように生成したい場合などに使うことができると思います.
配置エリアを可視化する
Gizmoを利用することで,配置エリアを可視化することができます.カメラには映らないので,シーンビューでの確認に使えます.スクリプトで設定した範囲を視覚的に確認できると安心できますよね!
例えば以下のスクリプトで立方体のGizmoを作成することができます.
public class writeGizmo : MonoBehaviour
{
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(transform.position, new Vector3(1, 1, 1));
}
}

よくあるエラー対処
よくあるエラーをいくつかご紹介します.
Prefabがセットされていない
NullReferenceExpectionと表示されます.Inspectorタブで正しいPrefabを設定してください.
範囲がゼロになっている
制限した範囲がゼロになり,ランダムな座標を取得できないというエラーです.
例えば立方体範囲を指定した時に2つの引数を同じにしてしまう(a = b)と生じます.
指定している範囲が有効であるかを確認してみましょう.
生成したオブジェクトが地面に埋もれる,浮いてしまう
y座標に適切な範囲を指定することで解決する場合がほとんどです.またオブジェクトの中心が原点になっていることを確認してください.