ドキュメント

Unity Engine

Unity Engine

ランダム性の使用

ランダムな クラスを使用して、ゲーム開発で一般的に必要とされるさまざまなタイプのランダムな値を生成します。
読み終わるまでの所要時間 17 分最終更新 3日前

ランダムなクラスは、一般的に必要とされるさまざまな種類のランダムな値を簡単に生成する手段を提供します。
このページでは、ランダムなクラスの概要と、このクラスを使用してスクリプトを作成する際の一般的な使用方法について説明します。ランダムなクラスのすべてのメンバーの詳細なリファレンスと、それに関する技術的な詳細については、ランダムなスクリプト リファレンスを参照してください。
これらの便利な方法の詳細と例については、以下のリンクを参照してください。

単純ランダムな数

Random.value
は、0.0 ~ 1.0 のランダムな浮動小数点数を指定します。一般的な使用方法は、結果を乗算して 0 から選択した範囲の数値に変換することです。
Random.Range
を指定すると、指定した最小値と最大値の間のランダムな数値が得られます。指定された最小値と最大値が int か float かに応じて、int か float のいずれかを返します。

円または球内のランダムな点

Random.insideUnitCircle
は、 半径 1 の円内でランダムに選択された点を返します (この場合も、 結果を乗算すると、 任意のサイズの円内のランダムな点が得られます) 。
Random.insideUnitSphere
は、 半径 1 のスフィア内でランダムに選択された点を返します 。
Random.onUnitSphere
は、 半径 1 の_スフィア_サーフェス上のランダムに選択された点を返します 。

その他のタイプのランダムな値

Unity のランダムなクラスは、他にもいくつかのタイプのランダムな値を提供します。
ランダムな回転を生成するには、
Random.rotation
を
使用します。
ランダムな色を生成するには、
Random.ColorHSV
を
使用します。

配列からランダムなアイテムを選択する

ランダムな配列要素の選択は、要約すると、0 と配列のインデックスの最大値の間のランダムな整数 (配列の長さから 1 を引いた値) の選択になります。これはビルトインの
Random.Range
機能を使用して簡単に行えます。
var element = myArray[Random.Range(0, myArray.Length)];
Random.Range
は、最初のパラメーターを含み、2 番目のパラメーターを除く範囲から値を返すため、ここで
myArray.Length
を使用すると正しい結果になります。

確率の異なるアイテムの選択

ランダムなアイテムを選択する必要がある場合がありますが、他のアイテムよりも選択される可能性が高いアイテムもあります。例えば、NPC がプレイヤーに遭遇すると、以下のような異なる反応を示す場合があります。
  • 50% の確率でフレンドリーな挨拶
  • 25% の確率で逃げる
  • 20% 確率で即座に攻撃
  • 5% 確率でお金をプレゼント
これらの異なる結果を、ストリップの長さの一部を占めるセクションに分割された紙切れとして視覚化できます。占める割合は、その結果が選択される確率に等しい。選択を行うことは、ストリップの長さに沿ったランダムな点を選択し (例えばダーツを投げるなど)、それがどのセクションに含まれるかを確認することと同じです。

A strip representing a probability space from 0% to 100% is split into four segments representing 50%, 25%, 20%, and 5% of the strip's length. A dart is embedded at the 82% point along the strip, inside the 20% segment.

スクリプトでは、短冊は実際には項目ごとに異なる確率を順番に含む float の配列です。ランダムな点は、
Random.value
に配列内のすべての float の合計を乗算することで得られます(合計が 1 になる必要はありません。重要なのは、異なる値の相対的なサイズです)。ポイントがどの配列要素に「含まれる」かを調べるには、まず、それが最初の要素の値より小さいかどうかを確認します。その場合、最初の要素が選択された要素になります。そうでない場合は、ポイント値から最初の要素の値を減算し、それを 2 番目の要素と比較し、正しい要素が見つかるまで比較を続けます。コードでは、外観は以下のようになります。
float Choose (float[] probs) { float total = 0; foreach (float elem in probs) { total += elem; } float randomPoint = Random.value * total; for (int i= 0; i < probs.Length; i++) { if (randomPoint < probs[i]) { return i; } else { randomPoint -= probs[i]; } } return probs.Length - 1;}
final return ステートメントは、
Random.value
が 1 の結果を返す可能性があるため必要です。この場合、検索ではランダムな点はどこにも見つかりません。行の変更:
if (randomPoint < probs[i])
... より小さいか等しいテストは余分なな return ステートステートメントを避けますが、確率が 0 の場合でもアイテムが時々選択されるようになります。

連続したランダムな値の重み付け

floatの配列メソッドは、結果が個別である場合はうまく機能しますが、より継続的な結果を生成する状況もあります。例えば、宝箱で見つかった金貨の数をランダム化し、1~100の間の任意の数で終了できるようにしたいが、数字を低くしたいなどです。これを行うには、float 配列メソッドを使用して 100 個の float の配列 (つまり、紙片上のセクション) を設定する必要がありますが、これは扱いにくく、整数に制限されず、代わりに範囲内の任意の数が必要な場合は、この方法を使用することはできません。
継続的な結果を得るためのより良いアプローチは、
AnimationCurve
を使用して「Raw」ランダムな値を「Weighted」値に変換することです。異なるカーブ形状を描画することで、異なるWeightingを生成できます。コードの記述も簡単です。
float CurveWeightedRandom(AnimationCurve curve) { return curve.Evaluate(Random.value);}
0から1の間の「Raw」ランダムな値は、
Random.value
から読み取ることによって選択されます。その後、
curve.Evaluate()
に渡され、水平座標として扱われ、水平位置のカーブに対応する垂直座標が返されます。カーブの浅い部分は選択される確率が高く、急な部分は選択される確率が低くなります。

A linear curve does not weight values at all; the horizontal coordinate is equal to the vertical coordinate for each point on the curve.

This curve is shallower at the beginning, and then steeper at the end, so it has a greater chance of low values and a reduced chance of high values. You can see that the height of the curve on the line where x=0.5 is at about 0.25, which means there's a 50% chance of getting a value between 0 and 0.25.

This curve is shallow at both the beginning and the end, making values close to the extremes more common, and steep in the middle which will make those values rare. Notice also that with this curve, the height values have been shifted up: the bottom of the curve is at 1, and the top of the curve is at 10, which means the values produced by the curve will be in the 1-10 range, instead of 0-1 like the previous curves.

これらのカーブは、確率論のガイドにあるような確率分布カーブではなく、むしろ逆累積確率カーブに近いことに注意してください。
スクリプトの 1 つにパブリック
AnimationCurve
変数を定義すると、値を計算する代わりに、Inspector ウィンドウでカーブを視覚的に確認および編集できます。
この技法は浮動小数点数を生成します。整数の結果を計算する場合 (例えば、82.1214 金貨ではなく 82 金貨が必要な場合)、計算した値を
Mathf.RoundToInt()
などの関数に渡します。

リストのシャッフル

一般的なゲームメカニクスは、既知のアイテムのセットから選択し、ランダムな順序でアイテムを入手するというものです。例えば、トランプは通常、予測可能な順序で描画されないようにシャッフルされます。各要素を参照し、配列内のランダムなインデックスの他の要素と入れ替えることで、配列内の項目をシャッフルできます。
void Shuffle (int[] deck) { for (int i = 0; i < deck.Length; i++) { int temp = deck[i]; int randomIndex = Random.Range(i, deck.Length); deck[i] = deck[randomIndex]; deck[randomIndex] = temp; }}

繰り返しのないアイテムのセットから選択する

一般的なタスクは、同じアイテムを複数回選択せずに、セットからランダムに複数のアイテムを選択することです。例えば、ランダムなスポーンポイントに複数の NPC を生成したいが、各ポイントに生成される NPC は 1 つだけにする必要があるとします。これを行うには、アイテムを順番に繰り返し、選択したセットに追加するかどうかをランダムに決定します。各アイテムが訪問されると、そのアイテムが選択される確率は、まだ必要なアイテム数をまだ選択可能なアイテム数で割った値になります。
たとえば、10 個のスポーン ポイントが利用可能で、5 個だけ選択する必要があるとします。最初のアイテムが選択される確率は 5/10 または 0.5 です。選択した場合、2 番目のアイテムの確率は 4/9 または 0.44 になります (つまり、4 つのアイテムがまだ必要で、残り 9 つから選択できます)。ただし、最初の 1 つが選ばれなかった場合、2 番目の確率は 5/9 または 0.56 になります (つまり、まだ 5 つ必要で、残り 9 つから選択できます)。これは、必要な 5 つのアイテムがセットに含まれるまで続きます。これは、コードで次のように実行できます。
Transform[] SpawnPoints;Transform[] ChooseSet (int numRequired) { Transform[] 結果 = new Transform[numRequired]; int numToChoose = numRequired; for (int numLeft = spawnPoints.Length; numLeft > 0; numLeft--) { float prob = (float)numToChoose/(float)numLeft; if (Random.value <= prob) { numToChoose--; result[numToChoose] = spawnPoints[numLeft - 1]; if (numToChoose == 0) { break; } } } return result;}
選択はランダムですが、選択したセット内のアイテムは元の配列と同じ順序になります。アイテムを 1 つずつ順番に使用する場合、順序は部分的に予測可能にします。そのため、使用前に配列をシャッフルする必要がある場合があります。

スペース内のランダムな点

三次音量のランダムな点は、Vector3 の各コンポーネントを
Random.value
によって返される値に設定することで選択できます。
var randVec = Vector3(Random.value, Random.value, Random.value);
これにより、辺が 1 単位の長さのキューブ内に点が与えられます。キューブは、VectorのX、Y、Zコンポーネントに希望する辺の長さを乗算するだけで拡大縮小できます。軸の 1 つが 0 に設定されている場合、点は常に 1 つの平面内にあります。例えば、「地面」上のランダムな点の選択は、通常、X コンポーネントと Z コンポーネントをランダムに設定し、Y コンポーネントを 0 に設定することです。
音量がスフィアの場合 (つまり、原点から所定の半径内のランダムな点が必要な場合)、
Random.insideUnitSphere
に目的の半径を乗算します。
var randWithinRadius = Random.insideUnitSphere * radius;
結果の Vector コンポーネントの 1 つを 0 に設定すると、円内のランダムな点は正しく取得_されない_ことに注意してください。点は確かにランダムで、正しい半径内にありますが、確率は円の中心に大きく偏っているため、点は非常に不均等にスプレッドします。このタスクには、代わりに
Random.insideUnitCircle
を使用する必要があります。
var randWithinCircle = Random.insideUnitCircle * radius;