Unity2019.3から使用可能なSerializeReference
と、
下記で公開くださっているSubclassSelector
がすっごい便利でしたので布教したくなりました。
SerializeReference
についても素晴らしく丁寧な説明をしてくださっています。
なお、今回の記事はUnity2020.2f1で動作を確認したものとなります。
使ってみた
/// <summary> /// SerializeReference用サンプルScriptableObject /// </summary> [CreateAssetMenu] public class Sample : ScriptableObject { [SerializeReference, SubclassSelector] private ISample[] _array; } /// <summary>サンプル用インターフェース</summary> public interface ISample { } /// <summary>サンプル用クラスA</summary> public class SampleClassA : ISample { [SerializeField] private string _name; [SerializeField] private int _value; } /// <summary>サンプル用クラスB</summary> public class SampleClassB : ISample { [SerializeField] private string _name; [SerializeField] private string _description; }
これが、こうな……る……? あれ?
しまった。基本的にどんなプロジェクトでもエディタ拡張アセットのOdinが使えるようにしているのでOdinアリの見た目になってました。
どうやらOdinさんはもともとSerializeReference
だと代入可能な型を選択できる機能が備わっていたようですね。
さすが大人気アセット。隙がねぇな。
さて、Odin無い通常バージョンでの見た目を改めて確認すると
期待した通りになってますね!
インターフェース型変数をシリアライズしたいんだよなぁというケースはめちゃくちゃあったので、これはすごくありがたいですね!
ちょっと改良してみる
仕事だと、実際にエディタで色々と調整を施すのはプランナーなのが多い、と思います。(小規模ならそうでもないことも多そうですけどね) なので、クラスの名前がそのまま表示されちゃうのはちょっと困るかも。そんなときは表示用のメタデータを
public class NameAttribute : Attribute { public string Name { get; } public NameAttribute(string name) => Name = name; }
/// <summary>サンプル用クラスA</summary> [Name("サンプルA")] public class SampleClassA : ISample { [SerializeField] private string _name; [SerializeField] private int _value; } /// <summary>サンプル用クラスB</summary> [Name("サンプルB")] public class SampleClassB : ISample { [SerializeField] private string _name; [SerializeField] private string _description; }
こうしてあげると
よさげ。
注意点
SerializeReference
はその名の通り、参照をシリアライズします。
そのため、SubclassSelector
は「指定された型のインスタンスを生成してその参照をシリアライズ」という手法を取っています。
SubclassSelectorDrawer.cs
を見ていただくとわかるんですが、インスタンスの生成にはActivator.CreateInstance
を使用しています。
Activator.CreateInstance
はnewと同じですしこれは正しいのですが、生成したい型に引数無しのコンストラクタが無いとエラーが出てしまいます。
(インスペクタ表示用のクラスにデフォルト以外のコンストラクタを用意するのは悪手だとは思いますけどね)
これについての説明と対処法はこちらの記事で解説しています。
余談
Unity2020.2f1で、順番入れ替え可能なReordableListがデフォルトで使えるようになっているようです。 前まではinternalで存在していて、知る人ぞ知るものだったんですが嬉しいですね。 またUnity2020.2からはC#バージョンも8に上がり(.NET Standardは2.0のままですが…)、Switch式など超便利な記述が多数可能になっていて、これも見逃せません。