Unify Community に InitializeOnLoadなどの良くある間違いに関する Tips があったので紹介したい:
http://wiki.unity3d.com/index.php/Tip_of_the_day
Feb 2013
Tip #55 InitializeOnLoad & Resources.Load gotcha’s
InitializeOnLoadおよびResources.Loadの良くある間違い
最近、 Unity 4 エディタで初めはバグだとおもった内容に遭遇した。 InitializeOnLoad からの Resources.Load メソッドの使用が絡んでいる。
例えば次のサンプルコードをみてみる:
namespace CBX.CoreProjectCode
{
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class EditorInitialization
{
static EditorInitialization()
{
LoadData(); // Resourceフォルダのtest.txt ファイルを参照することに失敗する
}
private static void LoadData()
{
// データのロードを試みる
var data = Resources.Load("test", typeof(TextAsset)) as TextAsset;
if (data == null)
{
Debug.LogWarning("データは見つかりませんでした");
return;
}
Debug.Log(data.text);
}
}
}
Unity がスクリプトをコンパイルした後、InitializeOnLoad によりマークされたクラスの static なコンストラクタを実行する。しかし、この時点で私は Unity がまだ Resources フォルダの中にあるアセットについては識別できていないとみている。クラスのコンストラクタが Resources.Load メソッドをコールしたとき、 text.txt リソースファイルを呼ぶことに失敗し、コンソールに警告メッセージを表示する。
この時点でやることが可能であることのひとつはプロジェクトウィンドウの Assets フォルダを右クリックして Reimport を選択することだ。 Unity は Assets を再インポートして、 InitializeOnLoad によりマークされたクラスをコールする。しかし、今回は Resources.Load は正しく test.txt の読み込みを行い、内容を Unity コンソールウィンドウに表示する。
この問題の回避方法のひとつは、 EditorApplication.Update コールバックをフックしてそこから LoadData メソッドへのコールを行うことだ。以下にそのサンプルを示す:
namespace CBX.CoreProjectCode
{
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class EditorInitialization
{
private static bool ranOnce;
static EditorInitialization()
{
EditorApplication.update += RunCallbacks;
}
private static void RunCallbacks()
{
if (!ranOnce)
{
// Resource フォルダの test.txt がみつかり内容が
// 表示される
LoadData();
ranOnce = true;
// returnするかはあなた次第
return;
}
// 必要な処理があれば記述
}
private static void LoadData()
{
var data = Resources.Load("test", typeof(TextAsset)) as TextAsset;
if (data == null)
{
Debug.LogWarning("データはみつかりませんでした");
return;
}
Debug.Log(data.text);
}
}
}
これがバグであるかどうかは認識していないが、Unity にバグレポートの提出は行っている。リンクは
次のとおりだ。
-----------------
先人の知恵は重要。Unity プログラミングに活かそうぜ!