目次
- 概要
- Random の使い方
- value, seed
- Range
- insideUnitCircle
- insideUnitSphere, onUnitSphere
- rotation, rotationUniform
- まとめ
概要
- C# には System.Random があるが、Unity ではそれを使用せず、別の Random クラスが用意されている
- [0, 1) の範囲、指定範囲の乱数生成に加え、球面上に位置する乱数を生成するなど、便利なメソッドが用意されている
※ [fist, last) は範囲を表す数学的記法。[first は first を含み(first 以上)、last) は last を含まない(last 未満)を表す。
Random の使い方
Unity の Random クラスは UnityEngine で定義されている。
UnityEngine.Random を使用するときは「using UnityEngine;」文が必要だが、
Unity で生成されるスクリプトには既にこの文が自動的に生成されているので、
新たに書き足す必要はなく、すぐに Random クラスを使用することができる。
Random のメンバ変数・関数はすべてスタティックである。複数の乱数生成器を同時に使用するようなことは出来ない。
簡単な使用方法
下記のように、式の右辺中で「Random.value」と記述すると、0 以上、1未満の float 型の乱数値(例えば、0.123 とか 0.753 とか)を生成してくれるぞ。
var r = Random.value; // [0, 1) 範囲の乱数値を生成
C/C++ の rand() などではランダムな seed を指定しないと、常に同じ系列の乱数を生成するが、 UnityEngine.Random はシードを指定しない場合でも、毎回違う系列の乱数を生成するようだ。
テスト時に固定の乱数系列にしたい場合は、以下のように Random.seed を指定するとよい。
Random.seed = 123; // 乱数シード指定 var r = Random.value; // [0, 1) 範囲の値(型は float)を生成
演習問題:
- Start() で、value を使って、float 型で [0, 10) 範囲の乱数を生成し、それを Debug.Log で表示してみなさい。
- 上記を何度も実行し、乱数系列が毎回異なることを確認しなさい。
- Start() で、seed を設定し、同じ乱数系列が生成されることを確認しなさい。
void Start () { var r = Random.value * 10; // float 型 [0, 10) の範囲の乱数を生成 Debug.Log(r); }
void Start () { Random.seed = 123; // シード指定 for(int i = 0; i < 5; ++i) { var r = Random.value; // float 型 [0, 1) の範囲の乱数を生成 Debug.Log(r); } }
整数乱数生成
Random.value は float 型なので、整数乱数が欲しい場合は、乱数の値を整数に型変換するとよい。
ただし Random.value を単純に整数に型変換すると、常に 0 になってしまうので、あらかじめ定数倍してからキャストで整数に変換する。
例えば、[0, 7) の範囲の整数乱数が欲しい場合は、以下のように記述するといいぞ。
int r = (int)(Random.value * 7); // [0, 7) の範囲の整数乱数を生成
指定範囲の乱数生成
[fist, last) 範囲の乱数を生成したい場合は、Range(first, last) 関数を使用する。
first, last の型は int または float で、Range() は引数と同じ型の乱数を返す。
※ value の場合は、常に float 型なので、整数に変換する必要があったが、Range(整数, 整数) で乱数を生成すれば、
自動的に整数乱数が得られる。便利ですなー
var ri = Random.Range(0, 10); // [0, 10) 範囲の整数乱数を生成
演習問題:
- start() で、Range を使って、float 型で [10, 20) 範囲の乱数を生成し、それを Debug.Log で表示してみなさい。
- start() で、Range を使って、int 型で [10, 20) 範囲の乱数を生成し、それを Debug.Log で表示してみなさい。
- start() で100個のキューブを x, y, z それぞれが [-10f, 10f) の範囲の乱数位置に生成しなさい(ヒント:キューブの生成は GameObject.CreatePrimitive(PrimitiveType.Cube) で行なう)。
void Start () { var r = Random.Random(10f, 20f); // float 型 [10, 20) の範囲の乱数を生成 Debug.Log(r); }
void Start () { var r = Random.Random(10, 20); // int 型 [10, 20) の範囲の乱数を生成 Debug.Log(r); }
void Start () { for(int i = 0; i < 100; ++i) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = new Vector3(Random.Range(-10f, 10f), Random.Range(-10f, 10f), Random.Range(-10f, 10f)); } }
円の内部のランダムな点を生成
Random.insideUnitCircle は、(Vector3型ではなく、)Vector2 型で、半径1の円の内部の点をランダムに生成します。
円の半径を指定したい場合は、Random.insideUnitCircle に半径を掛けます。
Vector2 を Vector3 に代入すると、x, y が代入され、z は 0 になるので、ゲームオブジェクトの transform.position に直接代入することが可能です。
ちなみに、円周上のランダムな点を生成する関数は用意されていないので、以下のように記述するといいでしょう。
※ Vector3 は3次元座標を保持するクラス。x, y, z メンバ変数を持つ。
Vector2 は2次元座標を保持するクラス。x, y メンバ変数を持つ。
const float PAI = 3.1415926535f; var theta = Random.Range(0f, 2*PAI); var r2 = new Vector2(Mathf.Cos(theta), Mathf.Sin(theta));
演習問題:
- Start() で100個のオブジェクトを z = 0 の x, y 平面上の半径10の円の内部にランダムに生成しなさい
void Start () { for(int i = 0; i < 100; ++i) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = Random.insideUnitCircle * 10; } }
球の内部または表面上のランダムな点を生成
Random.insideUnitSphere で半径1の球の内部の、Random.onUnitSphere で半径1の球の表面のランダムな点を生成する。
型はともに Vector3 だ。
以下は、半径10の球の表面上に、ランダムにオブジェクトを生成する例。
void Start () { for(int i = 0; i < 100; ++i) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = Random.onUnitSphere * 10; } }
演習問題:
- 中心が (0, 0, 0) 半径10の球表面の上部(y>=0)だけに、ランダムなオブジェクトを100個生成するコードを書きなさい
void Start () { for(int i = 0; i < 100; ++i) { Vector3 pos; do { pos = Random.onUnitSphere * 10; } while ( pos.y < 0 ); // y 座標がマイナスなら生成しなおし var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = pos; } }
ランダムな角度を生成
Random.rotation, Random.rotationUniform は Quaternion型のランダムな角度を返す。
この2つに違いは無いようだ。
以下の例は、オブジェクトの角度をランダムに設定するもの。
transform.rotation = Random.rotation; // 角度をランダムに設定
まとめ
UnityEngine.Random は整数・実数を単に生成するだけではなく、範囲を指定可能であったり、 円の内部・球の内部・表面や、(3次元空間での)角度をランダムに生成することができ、とても便利だぞ。