概要
Unityで他のクラスの参照を得る場合、MonoBehaviour.GetComponent を使うのは周知かと思います。
しかし、エディタ拡張で使う Editor を継承した場合など、MonoBehaviour に紐づかないクラスに対しては、GetComponentは使えません。
Editor(および EditorWindow)では、ScriptableObject.CreateInstance (公式ドキュメント参考:https://docs.unity3d.com/jp/current/ScriptReference/ScriptableObject.CreateInstance.html)
を使うことで実現できます。
Unityにおける標準的な機能と参照の取得
Unityで使われるスクリプトのほとんどは、 MonoBehaviour を継承しています。
Start()やUpdate()、コルーチンなどのUnityの標準的な機能は全てこの MonoBehaviour の機能であり、GetComponentもそのうちの一つです。
そのため、MonoBehaviourを継承しているクラスでは、 GetComponent によって参照が実現できます。
MonoBehaviour を継承しない場合の参照の取得
当然、MonoBehaviour を継承しない場合、GetComponent は使えません。
とはいえUnityの実装はC#なので、C#的にインスタンスを生成すれば、参照できます。
以下は、エディタ拡張で作ったウィンドウのボタンを押したときに参照したクラスの持つstringの中身をコンソールに書き出すというものです。
public class Example : EditorWindow {
// MonoBehaviourもなにも継承していないただのクラス
class InstanceTest
{
public string text = "Done";
}
[MenuItem("Tools/Example")]
static void Open()
{
EditorWindow.GetWindow<Example>("Example");
}
private void OnGUI()
{
if(GUILayout.Button("Test"))
{
// クラスのインスタンスを生成
InstanceTest instance = new InstanceTest();
Debug.Log(instance.text);
}
}
}
上のコードの実行結果は以下になります。
普通ですね。
Editorを継承したクラスを参照する
Editorで継承したクラスに対して、上と同じようにC#的に参照してみるとどうなるでしょうか。
まず、Editorを継承したクラスHoge.csを用意します。
using UnityEngine;
using UnityEditor;
public class Hoge : Editor {
public void HogeHoge()
{
Debug.Log("Hoge");
}
}
次に、ボタンを押したときに Hoge.cs の HogeHoge() を実行する Example.cs を用意します。
using UnityEngine;
using UnityEditor;
public class Example : EditorWindow {
[MenuItem("Tools/Example")]
static void Open()
{
EditorWindow.GetWindow<Example>("Example");
}
private void OnGUI()
{
if(GUILayout.Button("GetComponent"))
{
Hoge hoge = new Hoge();
hoge.HogeHoge();
}
}
}
実行結果は以下になります。
やりたいことはできていますが、何か怒られますね。内容的には
「ScriptableObject経由でインスタンス生成しろよバカ野郎」
といったところでしょうか。
実はこれは MonoBehaviour を継承したクラスに対して行っても同じようなことが起こります。
Unityでは非推奨ということですね。具体的に何がまずいのかは調査中ですが怒られないに越したことは無いので、Unityの想定しているやり方に直しましょう。
Editor や EditorWindow といったクラスは、これまたScriptableObjectを継承しています。
ScriptableObject には CreateInstanceという、MonoBehaviour の GetComponent 同様の機能がありますので、そちらを使って先ほどのコードを修正します。
using UnityEngine;
using UnityEditor;
public class Example : EditorWindow {
[MenuItem("Tools/Example")]
static void Open()
{
EditorWindow.GetWindow<Example>("Example");
}
private void OnGUI()
{
if(GUILayout.Button("GetComponent"))
{
Hoge hoge = ScriptableObject.CreateInstance<Hoge>();
hoge.HogeHoge();
}
}
}
使い方も GetComponent と同じですね。
実行結果は以下になります
エラーもなく無事に実行できましたね。
それでは快適なエディタ拡張ライフを!