こんにちは、Unityエンジニアのオオバです。

お悩みさん
お悩みさん
  • Editモード中のUnityでコルーチンを使いたい
  • コルーチンは実行中しか動かせない?
  • オオバ
    オオバ
    本記事ではこれらの悩みを解決します。

    結論から話すと、コルーチンは実行中のUnity上でのみ動きます。Editモード中(停止中のUnity)では基本的にコルーチンは動きません。しかしUnity公式が提供するパッケージ 「Editor Coroutines」 を使用することでEditモード中のUnityでも簡単にコルーチンを実行することができます。

    そこで本記事では Editor Coroutinesパッケージ の使い方から注意点まで詳しく解説します。エディタを拡張してEditモード中に通信をしたくなる時があるのです。通信とは非同期処理。非同期処理といえばコルーチンが候補にあがります。Editモード中のコルーチンは意外と需要が発生するため、スキルとして手に入れておくことをおすすめします。ぜひ最後まで読んでみてください。

    👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

    Editor Coroutinesのインストール

    本記事はUnity2021.3.0f1を使用していますが、Editor Coroutinesはデフォルトでインストールされています。ゆえに、特にインストール作業は発生しません。

    メニューWindow > Package Manager からPackage Managerウィンドウを開いてみましょう。Editor Coroutinesを探して選択してみてください。

    【Unity】Editモード中にコルーチンを実行する方法_0

    上図のように、Editor Coroutinesは削除しようにも「Remove」ボタンが押せない状態のため、間違ってアンインストールすることもないのです。つまり削除されることもないため安心してEditor Coroutinesを使っていきましょう。

    Editor Coroutinesの使い方

    ではEditor Coroutinesの具体的な使い方を解説します。例としてEditorWindow内でコルーチンを実行するサンプルを作ってみます。

    【準備】コルーチンを動かすEditorウィンドウの作成

    まずはTestWindowというEditorウィンドウを作ります。以下のソースコードを「TestWindow.cs」というC#スクリプトファイルを作成してコピペしてくみてください。

    using System.Collections;  
    using UnityEditor;  
    using UnityEngine;  
    
    public class TestWindow : EditorWindow  
    {
        [MenuItem("Test/TestWindow")]  
        private static void Init() => CreateWindow<TestWindow>().Show();  
    
        // カウントアップするコルーチン  
        private static IEnumerator CountUpCoroutine()  
        {
            var count = 0;  
            while (true)  
            {
                Debug.Log(count++.ToString());  
                yield return null;  
            }
        }
    }
    

    【Unity】Editモード中にコルーチンを実行する方法_1

    するとUnityのメニューに「Test」が追加されます。
    上図のように「TestWindow」をクリックしてEditorウィンドウを表示させておきましょう。

    【Unity】Editモード中にコルーチンを実行する方法_2

    このように空のEditorウィンドウが作られます。

    Editorウィンドウにボタンを追加

    このEditorウィンドウにボタンを追加してコルーチンを動かすトリガーを追加します。

    private void OnGUI()  
    {
        if (GUILayout.Button("Start", GUILayout.Height(30f)))  
        {
        }
    
        if (GUILayout.Button("Stop", GUILayout.Height(30f)))  
        {
        }
    }
    

    OnGUIメソッド内にEditorウィンドウ内の表示物を実装します。上記のコードをTestWindow.cs内に追加してください。

    【Unity】Editモード中にコルーチンを実行する方法_3

    すると、上図のようにボタンが2つ追加されました。このボタン処理の中にコルーチンの実行と停止処理を記述していきます。

    Editor Coroutinesでコルーチンを実行する方法

    Editモード中は通常のコルーチン実行メソッド「StartCoroutine」は動きません。代わりに EditorCoroutineUtility.StartCoroutine を使います。ではStartボタンをクリックしたらコルーチンが実行するようにコードを変更します。

    if (GUILayout.Button("Start", GUILayout.Height(30f)))  
    {
        EditorCoroutineUtility.StartCoroutine(CountUpCoroutine(), this);  
    }
    

    「EditorCoroutineUtility.StartCoroutine」の第1引数にコルーチン、第2引数にコルーチンを紐付けるオブジェクトを指定します。今回は「this」つまりTestWindow自身です。では、コルーチンを実行してみましょう。

    【Unity】Editモード中にコルーチンを実行する方法_4

    このようにConsoleウィンドウに、数値がカウントアップすることが確認できました。しかしこの状態ではコルーチンを止める事ができません。Editorウィンドウを閉じてもしばらく動き続けてしまいます。そこで次の章ではEditor Coroutinesのコルーチンの止め方を解説します。

    Editor Coroutinesのコルーチンの止め方

    Editor Coroutinesのコルーチンの止め方は通常のコルーチンと基本的に同じです。

    Editor Coroutinesの止め方

    ①EditorCoroutineをStartCoroutineの戻り値として受け取る

    ②StopCoroutineの引数にEditorCoroutineを渡す

    EditorCoroutineUtility.StartCoroutineメソッドの戻り値はEditorCoroutine型のインスタンスです。EditorCoroutineインスタンスをEditorCoroutineUtility.StopCoroutineの引数に渡すことでコルーチンは止まります。

    次のコードを見ていきましょう。

    // コルーチンを停止させるために保持する変数  
    private EditorCoroutine _coroutine;  
    
    private void OnGUI()  
    {
        if (GUILayout.Button("Start", GUILayout.Height(30f)))  
        {
            // コルーチンを開始  
            _coroutine = EditorCoroutineUtility.StartCoroutine(CountUpCoroutine(), this)  
        }
    
        if (GUILayout.Button("Stop", GUILayout.Height(30f)))  
        {
            // コルーチンを停止  
            EditorCoroutineUtility.StopCoroutine(_coroutine);  
        }
    }
    

    上記のコードを追加、編集することでStartボタン、Stopボタンにコルーチンの開始・停止を実装できます。

    Editorウィンドウを閉じるときにもコルーチンを止める方法

    Editorウィンドウを閉じたときにコルーチンを止めたい場合は、 OnDisable メソッド内に停止処理を書きましょう。

    void OnDisable()  
    {
        // Editorウィンドウを閉じたときにコルーチンを停止する  
        EditorCoroutineUtility.StopCoroutine(_coroutine);  
    }
    

    上記のソースコードを追加することでEditorウィンドウを閉じたタイミングでコルーチンは停止します。ぜひ覚えておきましょう。

    StopCoroutine以外のコルーチンの止め方

    StopCoroutine以外にも止め方が存在します。それは、EditorCoroutineUtility.StartCoroutineの第2引数オブジェクトをメモリから削除することです。次のコードを見てみましょう。

    if (GUILayout.Button("Start", GUILayout.Height(30f)))  
    {
        EditorCoroutineUtility.StartCoroutine(CountUpCoroutine(), new object())  
    }
    
    if (GUILayout.Button("Stop", GUILayout.Height(30f)))  
    {
        GC.Collect();  
    }
    

    StartCoroutineの第2引数を new object() としました。この状態でガベージコレクションを実行します(GC.Collectを実行)。するとメモリからobjectが削除されるためコルーチンは止まります。

    このテクニックが何かに使える気はしませんが、実装の仕組み自体を知っておくとどこかで役立つかもしれませんので、頭の片隅においておきましょう。

    Editor CoroutinesはWaitForSecondsが使えない

    Editor Coroutinesの注意点として、WaitForSecondsは使えません。WaitForSecondsとは指定した秒数処理を停止させるコルーチンの便利クラスです。

    private static IEnumerator CountUpCoroutine()  
    {
        var count = 0;  
        while (true)  
        {
            Debug.Log(count++.ToString());  
            // 10秒待機する処理  
            yield return new WaitForSeconds(10f);  
        }
    }
    

    上記のように10秒待機する処理を書いてみます。

    【Unity】Editモード中にコルーチンを実行する方法_5

    Editor Coroutinesを実行すると待機してくれません。

    そこで 「WaitForSecondsRealtime」 を使うのです。すると指定した秒数待機して処理が実行されるようになります。次のソースコードは 「WaitForSecondsRealtime」 を使った例です。

    private static IEnumerator CountUpCoroutine()  
    {
        var count = 0;  
        while (true)  
        {
            Debug.Log(count++.ToString());  
            yield return new WaitForSecondsRealtime(1f);  
        }
    }
    

    【Unity】Editモード中にコルーチンを実行する方法_6

    するとこのように指定秒数待機したコルーチンが実装できます。ぜひ覚えておきましょう。

    まとめ

    この記事ではEditモード中にコルーチンを使えるパッケージ「Editor Coroutines」について解説してきました。簡単に内容をまとめます。

    Editモード中にコルーチンを使う方法

    ①EditorCoroutineUtility.StartCoroutineでコルーチンを開始

    ②EditorCoroutineUtility.StopCoroutineでコルーチンを停止

    ③指定秒数待機するときはWaitForSecondsRealtimeを使う

    こんな感じです。

    Editor Coroutinesの使い方は基本的に通常のコルーチンと同じです。1度使ってみるとコルーチンに慣れている人であれば普通に使えるようになると思います。

    もし、Editモード中に非同期処理をはさみたい方は、Editor Coroutinesをぜひ使ってみてください。とても簡単にコルーチンを記述することができます。

    最後に今回使用したソースコード全文を共有します。

    using System.Collections;  
    using Unity.EditorCoroutines.Editor;  
    using UnityEditor;  
    using UnityEngine;  
    
    public class TestWindow : EditorWindow  
    {
        [MenuItem("Test/TestWindow")]  
        private static void Init() => CreateWindow<TestWindow>().Show();  
    
        private EditorCoroutine _coroutine;  
    
        private void OnDisable()  
        {
            // EditorWindowを閉じたらコルーチンが止まるようにする  
            StopEditorCoroutine();  
        }
    
        private void OnGUI()  
        {
            if (GUILayout.Button("Start", GUILayout.Height(30f)))  
            {
                StartEditorCoroutine();  
            }
    
            if (GUILayout.Button("Stop", GUILayout.Height(30f)))  
            {
                StopEditorCoroutine();  
            }
        }
    
        /// <summary>  
        /// 1秒ごとにカウントアップするコルーチン  
        /// </summary>  
        private static IEnumerator CountUpCoroutine()  
        {
            var count = 0;  
            while (true)  
            {
                Debug.Log(count++.ToString());  
                yield return new WaitForSecondsRealtime(1f);  
            }
        }
    
        /// <summary>  
        /// コルーチン開始  
        /// </summary>  
        private void StartEditorCoroutine()  
        {
            // コルーチンの二重実行回避用の条件分岐  
            if (_coroutine == null)  
                _coroutine = EditorCoroutineUtility.StartCoroutine(CountUpCoroutine(), this);  
        }
    
        /// <summary>  
        /// コルーチン停止  
        /// </summary>  
        private void StopEditorCoroutine()  
        {
            if (_coroutine == null) return;  
            EditorCoroutineUtility.StopCoroutine(_coroutine);  
            _coroutine = null;  
        }
    }
    

    この記事があなたのゲーム開発に少しでもお役に立てたら嬉しいです。

    オススメ記事
    検証環境