しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Unity 2022.2 以降でフィールド参照を維持しながらスクリプトを置き換える

※ これは 2023/01/06 時点の Unity 2022.2.1f1 の情報です

最新版では動作が異なる可能性がありますのでご注意ください

Unity 2022.2 以降での不都合をもう一つ見つけてしまった

Unity 2022.1.24f1 までは Inspector の Debug モードを有効にすると・・・

Inspector の Debug モードを有効に

例えば同じようなフィールドを持つ Test.cs の GameObject を Test2.cs にフィールド参照を維持したまま置き換えるというこができていたが

フィールド参照を維持したままスクリプト置き換えができない!

Script の値がグレーアウトされており、この技が使えなくなった!

便利だったので代替手段を用意したい

やることはただ一つ、Assets/Editor ディレクトリに下記のような ScriptReplacer.cs を記述し保存するだけ

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(MonoBehaviour), true)]
[CanEditMultipleObjects]
public class ScriptReplacer : Editor
{
    /// <summary>
    /// スクリプトのコンポーネントに UI を追加
    /// </summary>
    public  override void OnInspectorGUI()
    {
        // 現在のスクリプトを変更可能な UI として表示
        var selected = EditorGUILayout.ObjectField("Script Source", target, typeof(MonoScript), false);

        base.OnInspectorGUI();

        if (selected != null && selected is MonoScript script)
        {
            Replace(script);
        }
    }

    /// <summary>
    /// フィールド参照を維持したままスクリプトを置き換える
    /// </summary>
    /// <param name="toScript">置き換え後のスクリプト</param>
    private void Replace(MonoScript toScript)
    {
        var toClass = toScript.GetClass();
        Undo.SetCurrentGroupName($"Replace script");

        if (target is MonoBehaviour oldScript)
        {
            var obj = oldScript.gameObject;
            var newScript = Undo.AddComponent(obj, toClass);

            EditorUtility.CopySerialized(oldScript, newScript);

            Undo.DestroyObjectImmediate(oldScript);
        }
    }
}
#endif

これだけで Inspector から置き換え後のスクリプトを選択して置き換えできる

フィールド参照を維持したままスクリプト置き換え

これはかんたん