エディタ拡張をするとき、SerializedPropertyを使わずにやろうとするとなんかよくわからなくなりました。
ひょっとしたら、遠回りをしているのかも。
とりあえず、出来たんで、MEMO。
注:動画容量大です。
ちょっとわかりにくいかもしれませんが。
自作アセットのListを持っているアセットがあって、そのListのアセットもインスペクタ―から変更できるようにしたかったんです。
そして+ボタンを押せば、フォルダの中に自動でファイルが作られるように。
いちいちアセットを選択する手間を省きたかった。
困ったこと
- ファイルのパスの取得がうまくできない。
- アセットのスクリプトからの作り方がわからなかった。
- SerializedPropertyが使えないはず。
- 保存されない。
前回までの記事で、1と2については書きました。
のこり二つを書いていきます。
3.SerializedPropertyが使えないはず。
たぶんできないと思うんですけど。
ターゲットのオブジェクトが持つプロパティがあって、それがScriptableObjectだったとき。
public class TargetClass : ScriptableObject { [SerializeField] public string msg; [SerializeField] public int no; [SerializeField] public List<MyAsset> myAssetList; } [CreateAssetMenu(menuName =("createMyAsset"))] public class MyAsset : ScriptableObject{ [SerializeField] public Sprite m_Sprite; [SerializeField] public AudioClip m_Clip; }
僕が使ったのもこんな感じのフィールドを持つクラスだったんですが、このmyAssetListにインスペクタ―からアクセスできるようにしたかったんです。いちいち選択するのが面倒だったので。
FindProperty(“myAssetList”)でこれ自体はSerializedPropertyとして取得できます。
しかし、List<MyAsset>としては扱えない、はず。
型をキャストすることもできませんでした。多分。
どうするか?
public class TargetClassEditor : UnityEditor.Editor { TargetClass target; private void OnEnable() { target = (TargetClass)serializedObject.targetObject; }
こんな感じですれば、選択中のアセットをそのまま取得できます。
このtargetを参照しながら、EditorGUILayoutを使って、インスペクタ―の画面を作っていきます。
オブジェクト入力フィールド
List<MyAsset> myAssetList; private void OnEnable() { TargetClass target = (TargetClass)serializedObject.targetObject; myAssetList = target.myAssetList; } public override void OnInspectorGUI() { base.OnInspectorGUI(); EditorGUILayout.BeginVertical(); foreach(var row in myAssetList) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("m_Clip"); row.m_Clip = (AudioClip)EditorGUILayout.ObjectField( row.m_Clip, typeof(AudioClip), true); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("m_Sprite"); row.m_sprite = (Sprite)EditorGUILayout.ObjectField( row.m_sprite, typeof(Sprite), true); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); }
OnEnable()はインスペクタ―を開いたときに呼ばれます。
OnEnable()内で編集中のアセットを取得する必要があります。
serializedObject.targetObjectが編集中のオブジェクトになります。これを型キャストすれば取得できます。
そして、GUIを作りますが、SerializePropatyを使わない場合、これが面倒です。
EditorGUILayout.ObjectField()
オブジェクトの入力欄です。
2番目の引数に、参照するオブジェクトのタイプを入れます。例ではSpriteにしています。
3番目の引数のbool値はシーンからドロップされたオブジェクトをセットできるようにするかの値です。これを入れないと旧型式だとか言われて、なんかだめです。
取得するときに、型をキャストします。
これで、
よく見るオブジェクト入力フィールドができました。
しかし、これだけでは未完成です。
4.保存されない
使ってみます。
自分で作ったオブジェクトフィールドから、我らがアイドルゆにてぃちゃんを選択。
しかし、一度Unityを終了すると、
もう一度開いたとき、消えています。保存されていません。
この辺で、詰まりました。
解決策:
SetDirty()を追加します。
public override void OnInspectorGUI() { base.OnInspectorGUI(); EditorGUILayout.BeginVertical(); foreach(var row in myAssetList) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("m_Clip"); row.m_Clip = (AudioClip)EditorGUILayout.ObjectField( row.m_Clip, typeof(AudioClip), true); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("m_Sprite"); row.m_sprite = (Sprite)EditorGUILayout.ObjectField( row.m_sprite, typeof(Sprite), true); EditorGUILayout.EndHorizontal(); EditorUtility.SetDirty(row); } EditorGUILayout.EndVertical(); }
この色付きが追加した部分。
このSetDirtyの引数に変更したオブジェクトを入れます。
例の場合、(TargetClass)serializedObject.targetObjectを入れても保存されません。
TargetClass自体が持っているフィールドは保存されますが、フィールドのフィールド(この場合だとforeach中のrow)までは保存されません。
わかってみれば当たり前なのかもしれませんが、これがわからなくて散々迷いました。
あと、このままだと元に戻す処理ができません。
その場合はこちらの第12章あたりが参考になります。
上手く保存されなかったりした場合、上記リンクにあるUndo処理も記述する必要があるかもしれません。
以上で詰まったところは書き終わりました。
あとはAssetDatabaseなんかを応用して、ファイルが自動で作られたりするようにしました。その辺は、個別に考えるしかないと思います。
そんな感じで、エディタ拡張でした。
エディタ拡張としては、地味な変更だったかもしれませんが、非常に苦労しました。はっきり言って何もせずにそのまま変えた方がよかったんじゃないかと思うくらい。
完成したら、まあ便利だったんでやって良かったと思いましたけど。
慣れてきたらちょっとした入力補助は簡単にできそうです。
こまかく設定できるように、Unity側が用意してくれていますし。
やっぱりUnityすごい。開発環境すごい。
エディタ拡張したので、MEMO。
コメント