ゲームと乱数

ゲームにはほぼ必ず乱数が介入します。

つまりランダムな運による要素です。

双六ではサイコロを振り、人生ゲームではルーレットを回すでしょう。

デジタルなゲームでもRPGのドロップアイテム、敵とのエンカウント、回避の判定、

などをはじめとして枚挙に暇がありません。

乱数はゲームの結果を一定にせず、面白くするために必須の要素だと思います。

Unityと乱数

Unityには乱数を生成するクラスがあります。

以下の例の場合、0から99までの範囲でランダムな整数を返します。

using UnityEngine;

private void Awake()
{
	int random = Random.Range(0, 100);
}

float型のメソッドもあります。

System名前空間に、System.Randomというクラスも存在しますが、

今回はUnityEngine名前空間のUnityEngine.Randomの説明をしています。

シード値とは?

乱数を生成する機能を乱数生成器と言いますが、基本的な完全なら乱数では無く疑似乱数生成器です。

つまり、ランダムに見えて実は周期性と再現性を持っています。

周期性を感じさせないようにする、また再現性を持たせるために使用するのがシード(種)値です。

以下の例では、シード値を0としてるので、ログには毎回同じ値が出力されます。

using UnityEngine;
using Random = UnityEngine.Random;

private void Awake()
{
	Random.InitState(0);
	Debug.Log(Random.Range(0, 100));
}

できるだけランダムにするには現在時刻のミリ秒をシード値にするとよいかもしれません。

using System;
using UnityEngine;
using Random = UnityEngine.Random;

private void Awake()
{
	Random.InitState(DateTime.Now.Millisecond);
	Debug.Log(Random.Range(0, 100));
}

Minecraftというゲームにもシード値というものがありますが、これがワールドの生成ロジックに使用されているため、

通常ランダムに生成されるワールドもシード値を同じにするとこと他人と同じワールドを生成して遊ぶことが出来ます。

インスタンスを作りたい

Unity.Randomは別のインスタンスを作ることが出来ませんので、ゲーム中必ず単一の乱数生成器を使うことになります。

需要があるか分かりませんが、乱数生成器を分けたい場合には、Mathematicsパッケージを使います。

使用するバージョン

  • Mathematics 1.2.6

Package ManagerからMathematicsをインストールする

PackagerManagerを開いて、Mathematicsを探して、Installボタンを押します。

乱数生成器を生成する

using System;
using UnityEngine;

private void Awake()
{
	var random = new Unity.Mathematics.Random((uint)DateTime.Now.Millisecond);
	
	Debug.Log(random.NextInt());
}

Unity.Mathematics.Randomにシード値を与えると複数の乱数生成器を作ることが出来ます。

Unity.Randomクラスと違い、シード値はuint型になります。

Next〜系のメソッドはint,float以外にも沢山用意されています。

似たような乱数が出力される

先ほどのコードで乱数を出力してみると似たような値が出力されました。

シード値が近いとこのようになる特性があるようです。

その場合、CreateFromIndexメソッドを使って乱数生成器を作るといいかもしれません。

引数を元にメソッド内でハッシュ値を計算してそれをシード値としてくるようです。

using System;
using UnityEngine;

private void Awake()
{
    var random = Unity.Mathematics.Random.CreateFromIndex((uint)DateTime.Now.Millisecond);
    
    Debug.Log(random.NextInt());	
}

規則性を感じられなくなりました。

まとめ

  • 乱数を必要なら、UnityEngine.Randomが使える。
  • シード値で乱数は再現できる
    • 不具合を再現したい場合に固定のシード値を使えるようにするとデバッグに役立つかもしれません。
  • 複数の乱数生成器が必要なら、Mathematicsパッケージを使おう。