UnityEditor拡張勉強会 第1回 ～Prefabを大量に設置したい編～

# UnityEditor拡張勉強会 第1回 ～Prefabを大量に設置したい編～

社内のUnityクリエイター向けに、Editor拡張勉強会というものを実施しました！
せっかくなので、資料を公開します！

今後シリーズ化していく予定です！

# 本記事の対象

以下の方を対象としています。

- Unityでなにか制作・開発したことがある人
- Editor拡張を触ってみたけど、あまり自信がない人


# PrefabをPrefabのまま大量に設置したい！

以下のように、1つのPrefabをもとに、大量のGameObjectを一括で設置したい場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/b9d01e93-d2a9-c251-ac70-f4fe4c33efa4.png)

こういうときは、UnityのEditor拡張を使ってみましょう！

同じような状況で、 **Prefabのまま** 大量に設置したい場合もあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/387aae4f-f663-ecb9-c7ee-e4408e14b78e.png)


これもEditor拡張でできます！


# サンプルコード

今回つくったサンプルコードはこんな感じです。

```cs
using UnityEditor;
using UnityEngine;

public class InstantiatePrefabPracticeWindow : EditorWindow
{
    private GameObject originalPrefab;
    private GameObject parentGameObject;

    [MenuItem("Window/Instantiate Prefab Practice")]
    public static void InstantiatePrefabPracticeMenu()
    {
        GetWindow<InstantiatePrefabPracticeWindow>("Instantiate Prefab Practice");
    }

    private void OnGUI()
    {
        originalPrefab = EditorGUILayout
            .ObjectField("Original Prefab", originalPrefab, typeof(GameObject), false) as GameObject;

        parentGameObject = EditorGUILayout
            .ObjectField("Parent GameObject", parentGameObject, typeof(GameObject), true) as GameObject;

        if (GUILayout.Button("Instantiate as GameObject"))
        {
            InstantiateAsGameObject();
        }

        if (GUILayout.Button("Instantiate as Prefab"))
        {
            InstantiateAsPrefab();
        }
    }

    private void InstantiateAsGameObject()
    {
        for (var i = 0; i < 10; i++)
        {
            var clone = Instantiate(originalPrefab, parentGameObject.transform, true);
            clone.name = originalPrefab.name + i;
            clone.transform.SetSiblingIndex(i);
        }
    }

    private void InstantiateAsPrefab()
    {
        for (var i = 0; i < 10; i++)
        {
            var clone = PrefabUtility.InstantiatePrefab(originalPrefab) as GameObject;
            clone.transform.SetParent(parentGameObject.transform);
            clone.name = originalPrefab.name + i;
            clone.transform.SetSiblingIndex(i);
        }
    }
}
```

上記のサンプルコードを `Editor` フォルダー配下に置いてください。

`Window > Instantiate Prefab Practice` を選択すると、以下のようなウィンドウが開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/e044038b-1c8f-7a7e-09e6-c5ba1b2f6327.png)

`Original Prefab` 欄にお好きなPrefabを設置してください。

`Parent GameObject` 欄に親となるGameObjectを指定してください。

ボタンの役割は以下の通りです。

- `Instantiate as GameObject` : GameObjectとして設置する
- `Instantiate as Prefab` : Prefabのまま設置する


# 解説

## GameObjectとして設置したい

GameObjectとして設置したい場合はこちらの関数を使いましょう！

```cs
var clone = Instantiate(originalPrefab);
```

以下のようにGameObjectとして設置できます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/b9d01e93-d2a9-c251-ac70-f4fe4c33efa4.png)

## Prefabのまま設置したい

Prefabのまま設置したい場合はこちらを使いましょう！

```cs
var clone = PrefabUtility.InstantiatePrefab(originalPrefab) as GameObject;
```

以下のようにPrefabのまま設置できます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/387aae4f-f663-ecb9-c7ee-e4408e14b78e.png)

## 名前に番号をつけたい

以下のように、名前に番号をつけたいことがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/704a4c33-4a79-d82f-7ccb-96e360fc0e89.png)

そんなときは、以下のように `name` をつかえばいいです！

```cs
clone.name = originalPrefab.name + i;
```

## 番号順に並ばせたい

以下のように、番号順に並ばなくて困ることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/2f8edeb5-b132-695e-e0b1-2dbf8052c298.png)

そういうときは、 `transform.SetSiblingIndex()` を使えばいいです！

```cs
clone.transform.SetSiblingIndex(i);
```

これで、以下のようにキレイに整列します！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/704a4c33-4a79-d82f-7ccb-96e360fc0e89.png)

## 特定のGameObjectの配下に設置したい

以下のように、特定のGameObjectの配下に設置したいことがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/14db2e6d-f394-36a2-2d7d-6c5c96811a40.png)

そんな場合は、 `transform.SetParent()` を使いましょう！

```cs
clone.transform.SetParent(parentGameObject.transform);
```

こうすれば、 `parentGameObject` の配下に設置できます。

ちなみに、GameObjectとして設置する場合は、 `Instantiate` の引数に親を指定することもできます。

```cs
var clone = Instantiate(originalPrefab, parentGameObject.transform, true);
```

なお、Hierarchy内のGameObjectをEditor拡張のウィンドウで取得するためには、以下のように第4引数を `true` にする必要があるので、ご注意ください。

```cs
parentGameObject = EditorGUILayout.ObjectField("Parent GameObject", parentGameObject, typeof(GameObject), true) as GameObject;
```

# さいごに

今回はここまでです！おつかれさまでした！

本記事作成にあたり、以下のページを参考にしました。
ありがとうございました。

- https://docs.unity3d.com/ja/2017.4/ScriptReference/PrefabUtility.InstantiatePrefab.html