はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】Unity.Mathematics.Randomの使い方について網羅的に

はじめに

先日DOTSについての記事を書いていたのですが、UnityEngine.Random.Rangeを利用しようとしたら以下のようなエラーが出てきてしまいました。

UnityEngine::UnityException: RandomRangeInt can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
This Exception was thrown from a job compiled with Burst, which has limited exception support. Turn off burst (Jobs -> Burst -> Enable Compilation) to inspect full exceptions & stacktraces

まあUnity APIの大半はメインスレッドでしか動作しませんし、しゃあないですね。

代わりにUnity.Mathematics.Randomを使いましょうという流れになるわけですが、使い方は如何にというわけです。
github.com
docs.unity3d.com


今回はその辺りを紹介したいと思います。

環境

Mathematics 1.1.0

基本的な使い方

細かいことはいいから使い方を教えてほしい方向けに、以下の書き方を抑えればある程度使えると思います。

using UnityEngine;
using Random = Unity.Mathematics.Random;
public class RandomTest : MonoBehaviour
{
    private void Start()
    {
        // var random = new Random();              // シード値を0に設定するとArgumentExceptionを吐きます
        var random = new Random(100);              // シード値を100に設定

        random.InitState(200);                     // シード値を200に再設定する
        
        Debug.Log(random.NextInt());               // -2147483647以上, 2147483647以下の整数 [-2147483647, 2147483647]
        Debug.Log(random.NextInt(10));             // 0以上,10未満 [0, 10)
        Debug.Log(random.NextInt(0, 100));         // 0以上,100未満 [0, 100)
        
        Debug.Log(random.NextFloat());             // 0以上,1未満の小数 [0,1)
        Debug.Log(random.NextFloat(10));           // 0以上,10未満の小数 [0, 10)
        Debug.Log(random.NextFloat(0, 100));       // 0以上,100未満の小数 [0, 100)

        Debug.Log(random.NextDouble());             // 0以上,1未満の小数 [0,1)
        Debug.Log(random.NextDouble(10));           // 0以上,10未満の小数 [0, 10)
        Debug.Log(random.NextDouble(0, 100));       // 0以上,100未満の小数 [0, 100)
    }
}

もっと色々なメソッドについて

Unity.Mathematicsにはたくさんの型が存在しているので、それだけたくさんのメソッドが用意されています。

詳しくは公式ドキュメントに記載されていますが、このブログでも全部制覇しちゃおうという狂気の沙汰をしたいと思います。
Struct Random | Package Manager UI website

using UnityEngine;
using Random = Unity.Mathematics.Random;
public class RandomTest : MonoBehaviour
{
    private void Start()
    {
        // var random = new Random();               // シード値を0に設定するとArgumentExceptionを吐きます
        var random = new Random(100);               // シード値を100に設定

        random.InitState(200);                      // シード値を200に再設定する
        
        Debug.Log(random.NextBool());               // true or false
        Debug.Log(random.NextBool2());              // NextBool()の2次元配列版    各要素が同一な値というわけではなく、(true, false)のように4(=2^2)通りの内のどれか一つ
        Debug.Log(random.NextBool3());              // NextBool()の3次元配列版
        Debug.Log(random.NextBool4());              // NextBool()の4次元配列版
        
        Debug.Log(random.NextInt());                // -2147483647以上, 2147483647以下の整数 [-2147483647, 2147483647]
        Debug.Log(random.NextInt(10));              // 0以上,10未満 [0, 10)
        Debug.Log(random.NextInt(0, 100));          // 0以上,100未満 [0, 100)
        Debug.Log(random.NextInt2());               // NextInt()の2次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextInt3());               // NextInt()の3次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextInt4());               // NextInt()の4次元配列版 コンストラクタも3つありますが省略

        Debug.Log(random.NextFloat());              // 0以上,1未満の小数 [0,1)
        Debug.Log(random.NextFloat(10));            // 0以上,10未満の小数 [0, 10)
        Debug.Log(random.NextFloat(0, 100));        // 0以上,100未満の小数 [0, 100)
        Debug.Log(random.NextFloat2());             // NextFloat()の2次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextFloat3());             // NextFloat()の3次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextFloat4());             // NextFloat()の4次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextFloat2Direction());    // 長さ1の2次元ベクトルをランダムで返す めっちゃ便利
        Debug.Log(random.NextFloat3Direction());    // 長さ1の3次元ベクトルをランダムで返す めっちゃ便利


        Debug.Log(random.NextDouble());             // 0以上,1未満の小数 [0,1)
        Debug.Log(random.NextDouble(10));           // 0以上,10未満の小数 [0, 10)
        Debug.Log(random.NextDouble(0, 100));       // 0以上,100未満の小数 [0, 100)
        Debug.Log(random.NextDouble2());            // NextDouble()の2次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextDouble3());            // NextDouble()の2次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextDouble4());            // NextDouble()の2次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextDouble2Direction());   // 長さ1の2次元ベクトルをランダムで返す めっちゃ便利
        Debug.Log(random.NextDouble3Direction());   // 長さ1の3次元ベクトルをランダムで返す めっちゃ便利

        Debug.Log(random.NextQuaternionRotation()); // 長さ1のQuaternionを返します
        
        Debug.Log(random.NextUInt());                // 0以上, 4294967294以下の整数 [0, 4294967294]
        Debug.Log(random.NextUInt(10));              // 0以上,10未満 [0, 10)
        Debug.Log(random.NextUInt(0, 100));          // 0以上,100未満 [0, 100)
        Debug.Log(random.NextUInt2());               // NextUInt()の2次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextUInt3());               // NextUInt()の3次元配列版 コンストラクタも3つありますが省略
        Debug.Log(random.NextUInt4());               // NextUInt()の4次元配列版 コンストラクタも3つありますが省略
    }
}

抜けがなければこれで全部のメソッドを列挙できたはずです。

特に単位長のベクトルを返してくれるメソッドがあるのは少しビックリしましたが、かなり使い勝手は良さそうな気がします。

またUnityEngine.Randomと違ってシード値を設定できるので、再現性を必要とする場面でも活躍してくれそうですね。