はじめに
今回はScriptableObjectを使った一例を紹介したいと思います。
どんな例かというとインスペクターを使ったポリモーフィズムの実現です。
よくある例をみてから、それをどう改善していくかをみていきましょう。
シンプルなもの
まずはこの公式ドキュメントを参考にしながら、シンプルなポリモーフィズムを書いてみます。
docs.microsoft.com
using UnityEngine; public abstract class Shape { public abstract void Draw(); } public class Circle : Shape { public override void Draw() => Debug.Log("円を書いたよ"); } public class Rectangle : Shape { public override void Draw() => Debug.Log("四角を書いたよ"); } public class Triangle : Shape { public override void Draw() => Debug.Log("三角を書いたよ"); }
これを利用する側はこんな感じに実装しました。
using System.Collections.Generic; using UnityEngine; public class Drawer : MonoBehaviour { private List<Shape> _shapes = new List<Shape> { new Circle(), new Rectangle(), new Triangle() }; private void Start() { foreach(var shape in _shapes) { shape.Draw(); } } }
問題点
この実装方法だとそれぞれのインスタンスを管理するコレクションの初期化をコード側で書く必要があります。
private List<Shape> _shapes = new List<Shape> { new Circle(), new Rectangle(), new Triangle() };
Unityではインスペクターで設定するという強力なシステムがありますので、これを利用したいと考えました。
一番先に思いついた方法はShape
クラスにMonoBehavior
を継承させる手法ですが、それだけのためにコンポーネントを増やすのは愚作のような気もします。(MonoBehavoir自体大きいクラスですしね)
ここで思いついたのが、Shape
にScriptableObject
を継承させてしまうということです。
ScriptableObjectを使う
Shape
と各サブクラスを以下のように変更します。
using UnityEngine; public abstract class Shape : ScriptableObject { public abstract void Draw(); } [CreateAssetMenu] public class Circle : Shape { public override void Draw() => Debug.Log("円を書いたよ"); } [CreateAssetMenu] public class Rectangle : Shape { public override void Draw() => Debug.Log("四角を書いたよ"); } [CreateAssetMenu] public class Triangle : Shape { public override void Draw() => Debug.Log("三角を書いたよ"); }
ScriptableObject
を継承したのと[CreateAssetMenu]
を付けただけですね。
このようにすることで、各図形をアセットとして作成することができます。
利用する側
今度はこれらの図形を利用してみましょう。
using System.Collections.Generic; using UnityEngine; public class Drawer : MonoBehaviour { [SerializeField] private List<Shape> _shapes; private void Start() { foreach(var shape in _shapes) { shape.Draw(); } } }
こうすることで、どの図形をどの順番で実行するかを全てインスペクターから決定することができます。
付け足し
この記事ではみやすさのためにShape
とCircle
などのクラスを一緒に書いていますが、実際はきちんとスクリプトを分けて書いてください。
というものScriptableObject
にはクラス名とファイル名は同じにする必要があるからです。
忘れずにやっておきましょう。
さいごに
実はScriptableObject
を使ったことでまだまだ利点があります。
それはエディタ拡張がしやすいということで、インスペクターをみやすくしたり、アセット自体をエディタ拡張で作成したりなんかもできます。
上手に使えればかなり強力なのではないでしょうか。
またマサカリ等があればじゃんじゃんコメント等で教えていただけると嬉しいです。
ではまた。