UnityのEditorでコルーチンや非同期処理をする
Unityの拡張機能の方のEditorエディターのお話。エディターでの命令で非同期処理を行いたい時の対処法。自分の場合はツールでWebから取得したデータをローカルにcsvファイルとして吐き出させる処理を作るのに利用しました。
実装方法
UnityのEditorでコルーチン(StartCoroutine)などを行いたい場合、以下のEditorCoroutineというスクリプトをEditorフォルダ以下に作成して、「(namespace.)EditorCoroutine.start(呼びたい関数)」という感じで実装することで実現可能だそうです。
https://gist.github.com/benblo/10732554
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Swing.Editor
{
public class EditorCoroutine
{
public static EditorCoroutine start( IEnumerator _routine )
{
EditorCoroutine coroutine = new EditorCoroutine(_routine);
coroutine.start();
return coroutine;
}
readonly IEnumerator routine;
EditorCoroutine( IEnumerator _routine )
{
routine = _routine;
}
void start()
{
//Debug.Log("start");
EditorApplication.update += update;
}
public void stop()
{
//Debug.Log("stop");
EditorApplication.update -= update;
}
void update()
{
/* NOTE: no need to try/catch MoveNext,
* if an IEnumerator throws its next iteration returns false.
* Also, Unity probably catches when calling EditorApplication.update.
*/
//Debug.Log("update");
if (!routine.MoveNext())
{
stop();
}
}
}
}
実際に利用例のスクリプトもありました。Unityのビルド中は触らないほうが良さそうですが、EditorApplicationのUpdateに引っ掛ける方法は覚えておくと使い所がいつか出てきそう。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
using UnityEditor;
using Random = UnityEngine.Random;
namespace Swing.Editor.Test
{
public class TestEditorCoroutine
{
[MenuItem("Swing/Test/Test Editor Coroutine")]
static void testEditorCoroutine()
{
EditorCoroutine.start(testRoutine());
}
static IEnumerator testRoutine()
{
Debug.Log("hello " + DateTime.Now.Ticks);
yield return null;
Debug.Log("done " + DateTime.Now.Ticks);
}
[MenuItem("Swing/Test/Test Editor Coroutine With Exception")]
static void testEditorCoroutineWithException()
{
EditorCoroutine.start(testRoutineWithException());
}
static IEnumerator testRoutineWithException()
{
Debug.Log("hello " + DateTime.Now.Ticks);
yield return null;
for (int i = 0; i < 10; i++)
{
testRandomException();
yield return null;
}
Debug.Log("done " + DateTime.Now.Ticks);
}
static void testRandomException()
{
if (Random.value < 0.3f)
{
throw new Exception("ahah! " + DateTime.Now.Ticks);
}
else
{
Debug.Log("ok " + DateTime.Now.Ticks);
}
}
}
}
EditorCoroutine.startに指定する関数はIEnumerator型であればゲーム中に使っている処理でもそのまま当てはめることが出来ました。自分の場合は中でwww使って通信してその結果を扱う処理をしていたんですが、エディター用に変更する箇所もなかったのでかなり楽に実現出来ました。