Componentに必要な設定を自動で守らせるようにしたい

qiita.com

github.com

 Inspector上でResetすれば自動で必要な設定が揃うようにする、ということは今までやっていました。しかし、それでも面倒くさいのでもっと自動化しようとした取り組んだのが今回の記事。これでプロジェクトの最初からチェックルールを記述するようにしていけばかなり楽ができそうです。実際の説明はGitHubやQiitaに任せるとして、実装で躓いたことをメモ。

SceneをUnityEditor上でOpenせずに中身をいじる方法はないものか

 あるんですかね。

 今回の処理は、SceneとPrefabを全部チェック→必要があれば変更して保存する、という処理です。PrefabはAssetDatabase.LoadAssetAtPathを使って調査するだけでOK。しかし、Sceneに関しては上手な方法が見つかりませんでした。

 結局、UnityEditor上でSceneをOpenしてFindObjectsする方法を使いました。この方法の問題は、Scriptを実行したときにSceneを編集中だった場合に「編集内容を破棄するか」or「編集内容を強制保存するか」をしなくてはならないこと。とりあえず強制保存で実装しましたが、できれば避けたかったです。

既に開いているシーンを改めて開くとScriptが停止する

 エラーも出さずに中途半端なところで止まってしまいます。EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single)で空シーンを開いて対応。

Scriptによる変更が保存されない

 Scriptで変更した値が保存されない事態に遭遇しました。保存されてるように見えてもUnityを閉じて再度開くと元の値に戻ってしまう状態になりました。

 検索した結果「Undoクラスを使えば良い」や「SerializePropertyを使う」といった対応策が出てきましたが上手くいかず。結局EditorUtility.SetDirtyを使ったら上手く行きました。以下の記事が参考になりました。

www.urablog.xyz

 Componentに対してはEditorUtility.SetDirtyして、Sceneに対してはEditorSceneManager.MarkAllScenesDirtyしてから保存すると、Scriptによる変更が反映されました。

Scene内に配置されているPrefabに対する変更が保存されない

 前記の対応を行っても想定している動きにならなかったのが、Scene内に配置されたPrefabです。Scene内に配置されたPrefabは「元Prefabの値」に「変更値」分を上書きした状態になっています。この「変更値」分とScriptによる変更が重なっていると上手く行かないようでした。

 これは(1)一度Prefabのリンクを切って、(2)Scriptによる値の変更をして、(3)再度Prefabのリンクを繋げることで解決しました。リンクを切るのはPrefabUtility.DisconnectPrefabInstance、リンクを繋げるのPrefabUtility.ConnectGameObjectToPrefabです。リンクを繋げる方法はPrefabUtility.ReconnectToLastPrefabもあったのですが、こちらは上手く行きませんでしたね。