Unityでアセンブリリロード時に消えない値を保持するSessionStateの使い方をまとめました。
Unity2020.2.7f1
SessionState?
Unityエディタにおいて、ホットリロードの対象でない値はアセンブリリロード時に初期化されます。
例えば以下のようにInspector拡張に使っている値は、再生ボタンを押したときにリセットされます。
using UnityEditor; using UnityEngine; public class Example : MonoBehaviour { } [CustomEditor(typeof(Example))] public class ExampleEditor : Editor { // アセンブリリロード(再生ボタン押したりしたとき)にコレがfalseに戻る private bool _foldOut; public override void OnInspectorGUI() { _foldOut = EditorGUILayout.Foldout(_foldOut, "FoldOut"); if (_foldOut) { GUILayout.Label("Foo"); GUILayout.Label("Bar"); GUILayout.Label("Boo"); } } }
動作の様子は以下の通りです。再生時に折り畳みが解除されていることがわかります。
SessionStateを使うとアセンブリをリロードしても消えない値を保持しておけます。
また、アセンブリリロードしても消えないものの、Unityを閉じた時には消えてくれます。
内部的にはEditorPrefsが使われているようです。
使い方
それでは実際にSessionStateを使って前節の問題を解消します。
ソースコードは以下の通りです。
using UnityEditor; using UnityEngine; public class Example : MonoBehaviour { } [CustomEditor(typeof(Example))] public class ExampleEditor : Editor { private bool _foldOut; private bool _isInitialized; private static string FoldOutStateKey => $"{nameof(ExampleEditor)}{nameof(_foldOut)}"; public override void OnInspectorGUI() { if (!_isInitialized) { // SessionStateから値を取得する _foldOut = SessionState.GetBool(FoldOutStateKey, false); _isInitialized = true; } using (var ccs = new EditorGUI.ChangeCheckScope()) { _foldOut = EditorGUILayout.Foldout(_foldOut, "FoldOut"); if (ccs.changed) { // SessionStateに値を保存する SessionState.SetBool(FoldOutStateKey, _foldOut); } if (_foldOut) { GUILayout.Label("Foo"); GUILayout.Label("Bar"); GUILayout.Label("Boo"); } } } }
初期化時に値を取り出し、変更があったら値を保存しています。
動作の様子は以下の通りです。
再生しても折り畳みが解除されなくなりました。
ホットリロードについて
ホットリロードの対象となっている値についてはアセンブリリロード時にも値を保持します。
ホットリロードについては以下の記事にまとめていますので、必要に応じて参照してください。