【Unity】【エディタ拡張】エディタからシリアライズされたフィールドの値を更新する方法まとめ

エディタからシリアライズされたフィールドを更新する場合いくつか方法があります。
いずれかの方法を取らないとオブジェクトがDirtyであるとマークされず編集内容が保存されなかったりするのでまとめてみます。

基本はSerializedObject

エディタからシリアライズされた値にアクセスするといえばまずはSerializedObjectです。
下記のようにSerializedObject.FindProperty()でプロパティを取得して編集します。

var so = new SerializedObject(obj);
so.Update();
so.FindProperty("_sampleField").intValue++;
so.ApplyModifiedProperties();

この方法はシーンに置かれたオブジェクトでもProjectビューにあるアセットでも問題なく保存されます。
特にやらない理由がないのであればこの方法を取るのが良いと思います。

シーンオブジェクトのフィールドを直接編集する場合

コンポーネントのフィールドを直接編集する場合、
そのコンポーネントがアタッチされているオブジェクトがシーンに存在するなら、
Undo.RegisterCompleteObjectUndo()を使うことができます。

Undo.RegisterCompleteObjectUndo(obj, "set int");
obj.sampleField++;

これによりオブジェクトがDirtyであるとマークされ、Undoにも対応されます。

docs.unity3d.com

シーンオブジェクトのフィールドを直接編集する場合(Undoなし)

もしUndoをしたくない場合は下記のようにしてシーンをDirtyとしてマークします。

obj.sampleField++;
var scene = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene();
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(scene);

ちなみにですが、シーンの保存までしたければMarkSceneDirty()の後にSaveOpenScenes()を呼びます。

UnityEditor.SceneManagement.EditorSceneManager.SaveOpenScenes();

非シーンオブジェクトのフィールドを直接編集する場合

Projectビューに置かれているPrefabについているコンポーネントなど、シーン上に存在しないアセットのフィールドを
直接編集する場合は、EditorUtility.SetDirty()でオブジェクトをDirtyであるとマークします。

obj.sampleField++;
EditorUtility.SetDirty(obj);

なお上記のEditorUtility.SetDirty()はUndoに対応していません。
Undoに対応するには、Undo.RecordObject()を使用します。

docs.unity3d.com

ちなみに、アセットの保存までしたければSetDirty()の後にAssetDatabase.SaveAssets()を呼びます。

AssetDatabase.SaveAssets();