Unity の乱数のシードを保持している Random.State という型があります。
定義は以下の通りでシリアライズして保存することはできますが、中身を見ることはできません。中身を認識する必要は本来ありませんが、リフレクションを使えば中身を取得できそうです。ただ単純な構造体なので Unsafe.As が使えそうなので試してみようと思います。
namespace UnityEngine { [Serializable] public static class Random { [Serializable] public struct State { [SerializeField] int s0; [SerializeField] int s1; [SerializeField] int s2; [SerializeField] int s3; }
以下のように並び順が同じ(メモリレイアウトが同じ)構造体を用意して変換を実行し Random.State の内容を RandomState に移し替えます。
// RandomState.cs [System.Serializable] public readonly struct MyState { // Random.Stateと同じ並び順でフィールドを宣言する public readonly int s0; public readonly int s1; public readonly int s2; public readonly int s3; public MyState(int s0, int s1, int s2, int s3) { this.s0 = s0; this.s1 = s1; this.s2 = s2; this.s3 = s3; } public static implicit operator MyState(Random.State state) { return ToMyState(state); } // Random.State → MyStateに変換する public static MyState ToMyState(Random.State state) { return Unsafe.As<Random.State, MyState>(ref state); } // MyState → Random.Stateに変換する public static Random.State ToRandomState(MyState state) { return Unsafe.As<MyState, Random.State>(ref state); } // 内容を文字列に変換する public override string ToString() { return $"{nameof(s0)}={s0}, {nameof(s1)}={s1}, {nameof(s2)}={s2}, {nameof(s3)}={s3}"; } }
使い方は以下の通りです。
RandomState state = RandomState.Convert(Random.state); Log.Trace(state.ToString()); // Random.StateをMyStateに変換する MyState state1 = MyState.ToMyState(Random.state); Log.Trace(state1.ToString()); // s0=1282967314, s1=-563284738, s2=-1278752992, s3=241467906 // MyStateをRandom.Stateに戻す Random.State state2 = MyState.ToRandomState(state1);
Unsafe.As はコストがほぼゼロで高速かつ GCAlloc もゼロで動作するのでこれで簡単に中身の値がコピーされます。