エディタからフィールドを編集する
コンポーネントの状態を編集する
Unity コンポーネントは、コンポーネントの状態をエディタの「Inspector」ウィンドウ上に表示し、簡単にユーザーが編集できます。Visual Studio の利用者には、Visual Studio における「プロパティ」ウィンドウに相当する機能だと説明すればわかりやすいでしょう。
例えば、単にゲームオブジェクトを回転するスクリプトがあるとします。この時、フレームごと回転量をコード内にベタ打ちしてしまうと、回転速度の違うだけで別のスクリプトを用意することになってしまいます。適切な部品として再利用可能なスクリプトに仕立てるには、回転量をエディタから編集可能な状態として管理します。
ゲームオブジェクトに設定されたスクリプトの値を「Inspector」ウィンドウで編集できるようにする方法は、単に public なフィールドとして宣言すればよいだけです。フィールドが .NET Framework または Unity の型であれば、それだけで自動的に入力ボックスが「Inspector」ウィンドウ上に表示されます。
using UnityEngine; public class Test : MonoBehaviour { public float speed = 1; void Update () { transform.Rotate(0, speed, 0); } }
コード1は Y 軸に回転し続ける単純なスクリプトです。フレームごとの回転量は public な float 型の speed フィールドで決定しています。このスクリプトを任意のゲームオブジェクトに追加すると、「Inspector」ウィンドウに実行結果のような入力ボックスが表示されます。
このフィールドは、フィールド初期化子によって 1 に設定されているため、初期状態では 1 という値が表示されます。「Inspector」ウィンドウに表示されるフィールドの値は、他のコンポーネント同様にリアルタイムです。ゲームの実行中でも常に最新のフィールドの値が表示されますし、ゲーム実行中にフィールドの値を編集することもできます。
しかし、標準的な .NET Framework 開発者であれば参照型のフィールドを public に設定することに強い違和感を覚えることでしょう。public なフィールドは、どこから、どのようなタイミングで変更されるか予期できず、変更時に値の検証を行うこともできません。本来は、こうした問題を解決するためにフィールドを private にし、外部との取引にはプロパティを用います。
実行時に、外部のコードから適当にフィールドの値を書き換えられてしまう危険性は排除したいが、「Inspector」ウィンドウから値を編集できる利便性は捨てがたいものです。そこで、フィールドに対して UnityEngine.SerializeField 属性を設定します。
public sealed class SerializeField : System.Attribute
SerializeField 属性は MonoBehaviour クラスを継承するスクリプト内のフィールドに対して有効な属性です。この属性を持つフィールドはアクセス修飾子に関係なく「Inspector」ウィンドウから編集可能になります。
using UnityEngine; public class Test : MonoBehaviour { [SerializeField] private float speed = 1; void Update () { transform.Rotate(0, speed, 0); } }
コード2の実行結果はコード1と同じですが speed フィールドが private で修飾されている点が異なります。非公開のフィールドは既定では「Inspector」ウィンドウに表示されませんが、SerializeField 属性を付加することで public フィールドと同じように表示されます。
独自クラスを編集可能にする
数値や文字列、列挙体など .NET Framework の基本型や、ベクトルなどの数学型といった Unity エンジンの型は上記の方法で「Inspector」ウィンドウに表示され、簡単に編集できました。これ以外の独自に宣言したクラス型のフィールドなどは編集対象にはなりません。
ユーザー定義のクラスを「Inspector」ウィンドウから編集可能にするには、対象の型に対して System.SerializableAttribute 属性を指定します。スクリプトが SerializableAttribute 属性を持つクラス型のフィールドを公開している場合、「Inspector」ウィンドウではフィールドが展開可能になり、フィールドの子項目として対象のクラスの編集可能なフィールドが一覧表示されます。
using UnityEngine; using System; public enum Axis { None, X, Y, Z } [Serializable] public class RotateData { [SerializeField] private Axis axis; public Axis Axis { get { return axis; } set { axis = value; } } [SerializeField] private float speed; public float Speed { get { return speed; } set { speed = value; } } public RotateData(Axis axis, float speed) { this.axis = axis; this.speed = speed; } } public class Test : MonoBehaviour { [SerializeField] private RotateData rotation = new RotateData(Axis.X, 1); void Update () { if (rotation.Axis == Axis.X) transform.Rotate(rotation.Speed, 0, 0); else if (rotation.Axis == Axis.Y) transform.Rotate(0, rotation.Speed, 0); else if (rotation.Axis == Axis.Z) transform.Rotate(0, 0, rotation.Speed); } }
コード3の Test クラスが MonoBehaviour クラスを継承するスクリプトであり、このクラスは rotation フィールドを SerializeField 属性でマークしています。rotation フィールドは SerializableAttribute 属性が設定されている RotateData クラス型です。「Inspector」ウィンドウ上では Rotation 項目を展開すると RotateData クラスのフィールドを編集する項目が表示されます。このように、編集対象が単純型ではない場合はメンバが子項目として展開されます。