Editor拡張 - SeriazliedObjectに迫る
SerializedObjectとは
・Editor拡張で必須になるオブジェクト (裏を返せば普段の開発では使用しない)
・シリアライズ化されたパラメータにアクセスでき、値の編集が可能
privateなパラメータにもアクセスでき、値の編集が可能!
・Undo処理が自動で登録される
シリアライズ化とは
みなさんが良く書いている(と思われる)
[SerializeField]
public int _hoge;
これです。
具体的には
・public変数であること
または
・[SerializeField]のAttributeを付与している
です。
ただし、Unityがシリアライズ可能な型であること
型候補 | 型候補 |
---|---|
sbyte | float |
short | double |
int | bool |
long | char |
byte | string |
ushort | UnityEngine.Object |
uint | Serializable属性を付加したクラスや構造体 |
ulong | |
など |
・static, const, readonly, abstractクラスはシリアライズ化出来ません。
インスタンスの作り方
CustomEditorの場合は、特に指定しなくとも、そのオブジェクトのserializedObjectが格納されていることは説明しました。 (Editor拡張 - Windowを作ろう)
それを自分で作ろうとすると次のようにします。
var hoge = // Hogeクラスのコンポーネントを取得する
var serializedObject = new SerializedObject(hoge);
newして、引数にオブジェクトを入れるだけです。
物凄い簡単ですね。
使い方
実例
次のようなクラスがあった時にEditor拡張で値を編集したいとします。
public class Player : MonoBehaviour
{
[SerializeFiled]
private int _id;
public int _power;
private string _name;
}
var player = // Playerクラスのコンポーネントを取得
var serializedObject = new SerializedObject(player);
player.FindProperty("_power").intValue = 100;
player.FindProperty("_id").intValue = 1;
FindPropertyで「変数名」を入力して、適切な型の値を代入すればOKです。
豆知識
ちなみに「_name」プロパティはシリアライズしていないので、アクセスできません。
編集したい場合にどうしますか?
勿論、SerializeField属性を付与します。
ただし、単純に付与すると、Inspector上に表示したくなかったのに、表示されてしまいます。
そういう時は
[SerializeField, HideInspector]
private string _name;
HideInspectorのAttributeを使用しましょう。
データの反映について (重要)
同期の問題
前節で簡単に値の編集が出来ることが分かりました。
しかしながら、値の編集が同期されることを保証する必要があります。
急に難しいことを言われたような気がしますが、シンプルに考えると、例えば以下の状況で矛盾が発生します。
1. PlayerデータのInspetor上でSerializedObjectの値を編集している
2. 同時にPlayerデータを編集するための、自作のEditorWindowで値を編集している
SerializedObjectはインスタンス化した時に、そのオブジェクトのデータを格納するため、
自作のWindowを開いた後、Unity標準のInspector上で値を変更し、また自作のWindowに戻った時には古い情報のSerializedObjectのままです。
この時にWindowがそのまま値を保存すると、古いデータで更新されてしまいます。
解決策
解決策は凄く簡単です。
「値をいじる前」と「値をいじった後」に必ず、次の関数を呼びましょう。
1. serializeObject.Update
2. serializedObject.ApplyModifiedProperties
この2種類を下記のように実装するイメージになります。
public class NewBehaviourScript : Editor
{
public override void OnInspectorGUI()
{
// 内部キャッシュから最新のデータを取得する
serializedObject.Update();
EditorGUILayout.PropertyField (serializedObject.FindProperty ("name"));
// その他、様々な処理
// 内部キャッシュに変更点を適用する
serializedObject.ApplyModifiedProperties();
}
}
まとめ
SerializeObjectは、Editor拡張で値を変更する際に必須となるオブジェクト。
意外と使用方法はシンプルなので、是非覚えておきましょう。