【Unity】乱数のシード値を固定できるRandom.InitState

乱数のシード値 Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「乱数のシード値ってなに?」

「乱数のシード値を固定したい!」

というお悩みの方に向けた内容となっています。

Unityで乱数を使う場合に、シード値というものを使って、乱数を常に決まった値が取得されるように固定化することができます。

このシード値というのは、乱数を生成する際に指定するスタート地点を決めている値で、通常は現在の時間などが指定されて、常にランダムになるように設定されています。

Unityでは、このシード値をRandom.InitStateというメソッドで指定することで、何度実行しても同じ乱数を取得することができるようになります。

そこで、このページでは、Unityの乱数で使われるシード値について、どういうものなのか、またシード値を指定する方法までをまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

乱数のシード値ってなに?

まずは、乱数のシード値がどういうものなのか紹介していきます。

擬似乱数を生成する際の初期位置を表す値

乱数のシード値というのは、擬似乱数を生成する際の初期位置を決めている値のことです。

そもそもコンピューター上で乱数を生成する場合、サイコロの目のように完全にランダムな値を取得しているというわけではありません。

実際には、擬似乱数と呼ばれる特定の計算を行い、ランダムのように値が並んでいる数列を使って、順番に乱数を取得していきます。

そして、この擬似乱数の数列のどこから取得していくかを決めているのが、シード値という値になっていて、乱数の種とも呼ばれます。

このシード値が異なれば、取得する乱数のパターン(順番)も変わるので、ランダム的な要素を作ることができるようになります。

シード値を固定することで同じ状況を作り出せる

乱数のシード値を固定してあげることで、常に同じ乱数のパターンを取得することができ、ゲーム内処理において同じ状況を作り出すことができます。

例えば、乱数を使ってゲーム内の地形を作っていた場合、乱数のシード値が異なれば、当然作られる地形も異なることになります。

もし、全く同じ地形を生成したいという場合は、このシード値を固定してあげることで、乱数のパターンが常に同じものになるので、同じ地形を作り出すことができます。

ちなみに、乱数で地形を生成するような場合は、変動が滑らかな乱数を取得できるパーリンノイズ(PerlinNoise)というメソッドが使われることが多いです。

乱数のシード値を指定できるRandom.InitState

ここからは、乱数のシード値を指定することができるRandomクラスInitStateメソッドについて紹介していきます。

引数でシード値を指定して記述する

InitStateメソッドは、乱数のシード値を指定できるメソッドで、以下のように引数に値を入れて記述します。

Random.InitState(seed);

seed:乱数のシード値(int型)

InitStateメソッドの引数にシード値を整数で入れてあげることで、そのシード値を使って乱数を生成してくれるようになります。

例えば、擬似乱数を使って1~10までの値をランダムに取得して、コンソールウィンドウに表示させる処理を作ってみます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        for (int i = 0; i < 5; i++)
        {
            Debug.Log(Random.Range(0, 11)); // 乱数を取得して表示
        }
    }
}

まずは、上記のようにInitStateメソッドを使わずに、9行目でRandom.Rangeメソッドで取得してみると、以下のように2回実行するとそれぞれ異なる数値が表示されているのが分かります。

次に、シード値を固定した処理を作ってみます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        Random.InitState(10);   // 乱数のシード値を指定

        for (int i = 0; i < 5; i++)
        {
            Debug.Log(Random.Range(1, 11)); // 乱数を取得して表示
        }
    }
}

7行目でInitStateメソッドでシード値を指定する処理を行っています。

すると、以下のように2回実行してもどちらも同じ数値が表示され、シード値が固定できているのが分かります。

なお、シード値を指定しない場合は、Unity側で現在の時刻などからシード値が変わるようになっているので、ゲームを実行するたびに、毎回異なる乱数パターンで処理を行うことができます。

乱数を様々な処理で使う場合は注意

InitStateで乱数のシード値を指定することができますが、ゲーム内で複数の乱数を使った処理を作っている場合は注意が必要です。

なぜなら、このInitStateが定義されているRandomクラスというのは、シングルトンとなっていて、ゲーム内で一つしか存在しないクラスとなっているからです。

つまり、複数の処理で乱数を使う場合でも、一つのRandomクラスで生成された乱数を使ってそれぞれの処理が作られているということになります。

例えば、「地形の生成」「宝箱から出てくるアイテム」という2つの処理を、擬似乱数を使って作っている場合を考えてみます。

地形の生成を毎回同じものにしたいからと、InitStateでシード値を指定してしまうと、一つしかないRandomクラスのシード値が固定されることになります。

すると、地形の生成は毎回同じになりますが、宝箱から出てくるアイテムも全く同じものが出てきてしまい、ランダム的な要素が無くなってしまいます。

そのため、擬似乱数で複数の処理を作っている場合に、シード値を指定する際は注意しておきましょう。

もし、乱数を使って複数の処理を作り、シード値を固定するような場合は、それぞれの乱数の状態を保持する仕組みを別で作る必要が出てきます。

まとめ

このページでは、Unityの乱数のシード値について、どういうものなのか、また乱数のシード値を指定する方法までをまとめていきましたが、いかがでしたでしょうか?

乱数のシード値とは、Unityで生成される擬似乱数の開始位置を決めている値で、この値によって乱数のパターンが変わっています。

Unityで乱数のシード値を指定する場合は、Randomクラスで定義されているInitStateメソッドを使うことで、固定した乱数パターンを取得することができます。

ただし、乱数を複数の処理で使っているような場合は、それぞれの乱数の状態を保持させる仕組みを作る必要が出てきます。

最後までお読みいただきまして、ありがとうございました!

コメント