Help us understand the problem. What is going on with this article?

Editor拡張 - SeriazliedObjectに迫る

More than 3 years have passed since last update.

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拡張で値を変更する際に必須となるオブジェクト。
意外と使用方法はシンプルなので、是非覚えておきましょう。

messhi
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away