Unity Editor拡張でPrefabのセットアップを効率化

この記事は[カバー株式会社 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cover) 22日の記事になります。
## はじめに
私は23年度新卒で入社して、3D配信で使用するアプリとアセットの開発・運用をしています。業務の中で大量のアセットをセットアップすることがありました。セットアップには、Inspector上のSerializeFieldにオブジェクトをアサインする作業が含まれます。多くのオブジェクトに対して一つずつ手作業で設定を行うのは非効率で、ヒューマンエラーが発生しやすい作業です。

ここでEditor拡張の出番です。Editor拡張を使用すると、階層や命名規則の仕様が決まっていれば、大量のモデルやオブジェクトに共通の設定を一括で適用することができます。例えば、ホロライブJPの共通衣装のプレハブそれぞれに同一のスクリプトをつける場合、30以上のプレハブに同じ作業をする必要が出てきます。これらのプレハブを自動でセットアップするEditor拡張を作成することで設定作業を大幅に効率化できます。自動化は時間の節約だけでなく、エラーの減少にも繋がり、開発プロセスの質を向上させます。Editor拡張のカスタマイズにより、特定のプロジェクトのニーズに合わせた柔軟なワークフローを構築することが可能です。

## 簡易的なEditor拡張の実装
本記事では、Editor拡張のみ注目して、サンプルスクリプトを作成しました。なのでセットアップしたあとの具体的な処理は実装していません。
以下のようなプレハブにスクリプトのアタッチとSerializeFieldにオブジェクトをアサインする想定で実装しました。

![2023-12-18_17h39_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632682/a3f98478-00a5-0970-d985-00c88acb6caf.png)

![2023-12-18_17h32_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632682/c8a5bc0d-3836-a01f-93d6-ea88f6b37197.png)

一つのプレハブに対してこの作業は短時間で行うことができますが、大量(数十～数百)のプレハブに対してこの操作をする場合は多くの時間を要します。また、モデルに変更があった場合はアサインのやり直しの可能性もあります。Editor拡張を作成しておけば、モデルの変更にも少ない作業量で対応することができます。
スクリプトのアタッチとSerializeFieldにオブジェクトをアサインする作業を自動化するEditor拡張を実装してみました。

```csharp:PrefabSetupTool.cs
using UnityEngine;
using UnityEditor;

public class PrefabSetupTool
{
    [MenuItem( "Assets/Add SampleScript and Assign GameObject", false, 1 )]
    private static void AddSampleScriptAndAssignGameObject()
    {
        string targetObjectName = "TargetObject";
        foreach( Object selectedAsset in Selection.objects )
        {
            GameObject selectedGameObject = selectedAsset as GameObject;

            if( selectedGameObject != null )
            {
                Transform childTransform = selectedGameObject.transform.Find(targetObjectName);
                if( childTransform == null )
                {
                    Debug.LogError( "Target object not found in " + selectedGameObject.name );
                    continue;
                }

                GameObject gameObjectToAssign = childTransform.gameObject;
                SerializeFieldSample sampleScript = selectedGameObject.GetComponent<SerializeFieldSample>();
                if( sampleScript == null )
                {
                    sampleScript = selectedGameObject.AddComponent<SerializeFieldSample>();
                }

                SerializedObject serializedObject = new SerializedObject(sampleScript);
                SerializedProperty serializedProperty = serializedObject.FindProperty("m_SerializedGameObject");

                if( serializedProperty != null )
                {
                    serializedProperty.objectReferenceValue = gameObjectToAssign;
                    serializedObject.ApplyModifiedProperties();
                    Debug.Log( "Assigned GameObject and added SampleScript to " + selectedGameObject.name );
                }
            }
            else
            {
                Debug.LogError( "Selected asset is not a GameObject." );
            }
        }
    }
}

```
```charp:SerializeFieldSample.cs
using UnityEngine;

public class SerializeFieldSample : MonoBehaviour
{
	[SerializeField]
	private GameObject m_SerializedGameObject;
}

```
簡単のために、アタッチするスクリプトは具体的な処理は含まれていません。具体的な処理を書くとすれば、例えば、SerializeFieldにアサインされたオブジェクトの表示・非表示をコントロールする関数を実装するなどで活用できそうです。

### 使ってみる
セットアップしたいプレハブを選択して右クリックしてメニューを表示します。
メニューの中からAdd SampleScript and Assign GameObjectを選択します。

![2023-12-18_17h30_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632682/78876667-a281-482c-5a52-b4a344682753.png)

選択したプレハブすべてにスクリプトがアタッチされ、プレハブ内の名前が"TargetObject"のオブジェクトがSerializeFieldにアサインされます。

![2023-12-18_17h32_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632682/c8a5bc0d-3836-a01f-93d6-ea88f6b37197.png)

## まとめ
本記事では、簡易なサンプルスクリプトを作成して基本的なUnityのEditor拡張を実装してみました。大量の単純作業が発生する場合はEditor拡張が有効な場合が多いです。ただし、今回のようにオブジェクトの階層や命名規則が関わる場合は、3Dモデラーさんとも連携しながら、仕様を決定することが必要になります。実際の業務では、本記事のサンプルより設定する項目が多いため、より威力を発揮します。
Editor拡張の入門的な内容でしたが、単純作業にうんざりしている方の参考になれば幸いです。