スクリプトから UnityEditor を再生する場合は以下の処理をすればよい
EditorApplication.isPlaying = true;
しかし、UnityEditor が再生されるタイミングで、static なインスタンスが初期化されるため、Unity API にイベントを登録してあったとしても消えてしまう
そのため、以下の処理は正しく実行されず再生されたままになってしまう
EditorApplication.isPlaying = true; var count = 10000; EditorApplication.update += While; void While() { if (--count > 0) return; EditorApplication.update -= While; EditorApplication.isPlaying = false; };
ここで利用できるのが EditorWindow.OnEnable
と EditorApplication.playModeStateChanged
である
UnityEditor を再生時に EditorWindow.OnEnable
が呼び出されるのでこのタイミングで
EditorApplication.playModeStateChanged
に登録すればいい感じに再生後処理をすることができる
public class PlayStopLoopTool : EditorWindow { private void OnEnable() { EditorApplication.playModeStateChanged += PlayModeStateChanged; } private void PlayModeStateChanged(PlayModeStateChange stateChange) { switch (stateChange) { case PlayModeStateChange.EnteredEditMode: // ここでなら Unityの static なイベントに登録しても削除されない break; } }
指定回数再生と停止を繰り返すサンプル
先程の処理を利用して、再生停止を指定回数繰り返す EditorWindow のサンプルが以下になる
PlayLoopCount
を指定して 「Play」を押すと残り回数と停止するまでの時間が表示される
using System; using UnityEditor; using UnityEngine; public class PlayStopLoopTool : EditorWindow { [MenuItem("Tools/PlayStopLoop")] private static void ShowWindow() { var window = GetWindow<PlayStopLoopTool>(); window.Show(); } /// <summary> /// このタイミングで登録しないと再生時にイベントが消える /// </summary> private void OnEnable() { EditorApplication.playModeStateChanged += PlayModeStateChanged; } private void OnDisable() { EditorApplication.playModeStateChanged -= PlayModeStateChanged; } private void PlayModeStateChanged(PlayModeStateChange stateChange) { if (!_isPlaying) return; switch (stateChange) { case PlayModeStateChange.EnteredEditMode: Play(); break; case PlayModeStateChange.ExitingEditMode: break; case PlayModeStateChange.EnteredPlayMode: EndCheck(); break; case PlayModeStateChange.ExitingPlayMode: break; } } /// <summary> /// 再生する /// </summary> private void Play() { EditorApplication.isPlaying = true; // これ以降再生が始まると シリアライズされてないものは初期化される // そのため EditorApplication.update を利用していたら呼ばれなくなってしまう } /// <summary> /// 終了待ち /// </summary> private void EndCheck() { _endTime = DateTime.Now.AddSeconds(5); EditorApplication.update += Wait; } private void Wait() { Repaint(); if (DateTime.Now < _endTime) return; EditorApplication.update -= Wait; _restPlayCount--; EditorApplication.isPlaying = false; if (_restPlayCount <= 0) Debug.Log("終了しました"); } private int _playLoopCount = 1; private int _restPlayCount; private DateTime _endTime; private bool _isPlaying => _restPlayCount > 0; private void OnGUI() { _playLoopCount = EditorGUILayout.IntField("PlayLoopCount", _playLoopCount); using (new EditorGUI.DisabledScope(_playLoopCount <= 0)) { if (GUILayout.Button("Play")) { _restPlayCount = _playLoopCount; Play(); } } if (_isPlaying) { EditorGUILayout.LabelField($"残り {_restPlayCount}回"); if (_endTime > DateTime.Now) EditorGUILayout.LabelField($"終了まで {(_endTime - DateTime.Now).TotalSeconds:F}s"); } } }