この記事について

この記事では、UnityのInstantiate()でPrefabを生成する方法を解説します。弾丸や敵、エフェクトなどを、ゲーム中にスクリプトから配置したいときに使う基本の関数です。

基本はInstantiate(prefab)。位置と回転を決めるならInstantiate(prefab, position, rotation)、親も決めるなら最後に親のTransformを指定します。今回は、そのまま生成・位置と回転を指定・親を指定の3パターンを順番に見ていきましょう。

この記事でわかること

  • Prefabの作り方と、Inspectorへの割り当て方
  • InstantiateでPrefabを生成する3つのパターン
  • 親を指定したときのワールド座標とローカル座標の違い
  • 生成されない・位置がずれるときに確認すること

Prefabとは?

Prefab(プレハブ)は、再利用できるGameObjectのテンプレートです。見た目やコンポーネントなどをまとめて保存できるため、同じ敵キャラやアイテムを何度も出したいときに便利です。

UnityのPrefabアセットのInspector。位置と回転は0、Scaleは3

Instantiateとは?基本構文と戻り値

Instantiateは、指定したオブジェクトを複製して、生成したオブジェクトを返す関数です。ここではProjectビューに保存したPrefabを、シーン上に生成します。

GameObject createPrefab = Instantiate(prefab);

prefabがコピー元、createPrefabが生成したGameObjectです。生成後に位置を変えたい場合などは、この戻り値を使って操作できます。

位置と回転を省略すると、コピー元の位置・回転を引き継ぎます。原点に固定されるわけではありません。また、親を指定しなければ、生成したオブジェクトに親は付きません。詳しい引数はUnity公式のInstantiateリファレンスでも確認できます。

Prefabとスクリプトの準備

CubeをPrefabにする

今回はCubeを使います。位置の違いがわかるよう、次の状態にしておきましょう。

  1. Hierarchyの最上位に空のGameObject「Parent」を作成し、Positionを(3, 3, 3)、Rotationを(0, 0, 0)、Scaleを(1, 1, 1)にする
  2. Parentの子ではなく、Hierarchyの最上位にCubeを作成して「Prefab(Cube)」と名付ける。PositionとRotationを(0, 0, 0)、Scaleを(3, 3, 3)にする
Prefab化するCubeのTransformを設定したUnityの準備画面

ここまでできたら、HierarchyのPrefab(Cube)をProjectビューのAssets内へドラッグします。これでPrefabアセットを作成できます。シーンに置いたCubeは今回の確認では不要なので、Hierarchy側のPrefab(Cube)だけを削除しましょう。ProjectビューのPrefabは残しておきます。

この記事の画像・動画は、元の記事に掲載した作成・生成例です。追加した未設定チェックなど、コードの細部は本文を基準にしてください。

スクリプトをアタッチしてPrefabを割り当てる

  1. C#スクリプトを作成し、ファイル名をPrefab_Instantiate.csにする
  2. 次の「1. Prefabをそのまま生成」のコードを貼り付けて保存する
  3. Hierarchyに空のGameObject「Spawner」を作り、スクリプトをアタッチする
  4. SpawnerのInspectorで、Prefab欄にProjectビューのPrefab(Cube)をドラッグする。Create Prefab欄は実行後の確認用なので空欄のままでよい
  5. 「3. 親オブジェクトを指定して生成」のコードを使うときは、Obj Parent欄にHierarchyのParentも割り当てる

3つのコードは、同じPrefab_Instantiate.csを丸ごと差し替えて試す例です。同じクラスを複数のファイルに作らず、1つずつ使ってください。差し替え後はInspectorの割り当ても確認します。生成用スクリプトはSpawnerだけに付け、生成されるPrefabには付けません。

Prefabの割り当てとスクリプトのアタッチは、Unity公式のPrefab生成の手順でも紹介されています。

InstantiateでPrefabを生成する3つのパターン

1. Prefabをそのまま生成

まずは、Prefabだけを指定して生成する方法です。この例では、生成したあとで位置と回転を設定しています。

using UnityEngine;

public class Prefab_Instantiate : MonoBehaviour
{
    // Inspectorで指定するPrefab
    public GameObject prefab;
    // 生成されたオブジェクト(実行前は空欄でOK)
    public GameObject createPrefab;

    void Start()
    {
        if (prefab == null)
        {
            Debug.LogError("Prefab欄にProjectビューのPrefabを指定してください。", this);
            return;
        }

        // Prefabを複製して、生成されたGameObjectを受け取る
        createPrefab = Instantiate(prefab);

        // 生成したあとで、ワールド座標と回転を変更する
        createPrefab.transform.position = Vector3.zero;
        createPrefab.transform.rotation = Quaternion.identity;
    }
}

Instantiate(prefab)で複製したあと、positionをVector3.zeroに変更しているため、この例では最終的にワールド座標(0, 0, 0)へ移動します。最後の2行を外せば、コピー元の位置・回転を使います。

Quaternion.identityは「回転なし」を表す値です。コピー元の回転をそのまま使う指定ではありません。Quaternion.identityの公式説明も参考にしてください。

Playにして、Hierarchyに生成されたPrefab(Cube)(Clone)と、SpawnerのCreate Prefab欄を確認しましょう。動画でも、生成時の変化を確認できます。

生成後に位置を変える場合、Prefab側のAwakeやOnEnableは変更前に呼ばれることがあります。最初から決まった座標・回転で生成したい場合は、次の書き方を使います。

2. 位置と回転を指定して生成

次に、位置と回転を引数で指定します。敵を決まった場所に出したり、弾やエフェクトの向きを決めたりするときに使う書き方です。

using UnityEngine;

public class Prefab_Instantiate : MonoBehaviour
{
    public GameObject prefab;
    public GameObject createPrefab;

    void Start()
    {
        if (prefab == null)
        {
            Debug.LogError("Prefab欄にProjectビューのPrefabを指定してください。", this);
            return;
        }

        Vector3 pos = new Vector3(-1f, -1f, -1f);
        Quaternion rot = Quaternion.Euler(45f, 0f, 0f);

        // 指定したワールド座標・回転で生成する
        createPrefab = Instantiate(prefab, pos, rot);
    }
}

このコードでは、ワールド座標(-1, -1, -1)、X軸を45度回転した状態で生成します。Quaternion.Eulerは、度数で指定した角度から回転を作るための関数です。今回は親を指定していないので、Hierarchyの最上位に生成されます。

動画では、指定した位置・回転での生成例を確認できます。

3. 親オブジェクトを指定して生成

生成したオブジェクトをParentの子にしたい場合は、親のTransformも渡します。敵を管理用オブジェクトの下にまとめたり、UIを決まった階層に配置したりするときに便利です。

using UnityEngine;

public class Prefab_Instantiate : MonoBehaviour
{
    public GameObject prefab;
    public GameObject createPrefab;
    // Inspectorで指定するシーン内のParent
    public GameObject Obj_Parent;

    void Start()
    {
        if (prefab == null || Obj_Parent == null)
        {
            Debug.LogError("Prefab欄とObj_Parent欄を指定してください。", this);
            return;
        }

        Vector3 pos = new Vector3(-1f, -1f, -1f);
        Quaternion rot = Quaternion.Euler(45f, 0f, 0f);

        // ワールド座標・回転と、親のTransformを指定する
        createPrefab = Instantiate(prefab, pos, rot, Obj_Parent.transform);
    }
}

親に渡すのはGameObjectではなくTransformなので、ここではObj_Parent.transformを指定しています。

この4引数の書き方では、posとrotはワールド座標・ワールド回転です。Parentからの相対位置ではありません。今回の準備ではParentの位置が(3, 3, 3)なので、子のワールド座標が(-1, -1, -1)なら、InspectorのPositionはローカル座標の(-4, -4, -4)になります。これはParentの回転が(0, 0, 0)、Scaleが(1, 1, 1)の場合です。

動画では、Hierarchyの親子関係とInspectorのPositionを見比べてみてください。

親だけを指定する場合は、上のコードの生成行を次の1行に差し替えます。

createPrefab = Instantiate(prefab, Obj_Parent.transform);

この書き方はfalseを指定した場合と同じです。コピー元のローカル位置・回転(localPosition / localRotation)を引き継ぎ、指定した親を基準に配置します。今回のPrefabは位置(0, 0, 0)なので、Parentと同じワールド位置(3, 3, 3)に配置されます。

コピー元のワールド位置・回転を維持して親を付けたい場合は、代わりにtrueを指定します。

createPrefab = Instantiate(prefab, Obj_Parent.transform, true);

今回のPrefabは位置(0, 0, 0)なので、trueならワールド位置(0, 0, 0)を保ち、Parentの子になります。親を指定するときは、親からの相対位置を使うのか、ワールド位置を保つのかを決めておくと迷いません。

  • Instantiate(prefab, parent)/Instantiate(prefab, parent, false):コピー元のローカル位置・回転を引き継ぎ、親基準で配置する
  • Instantiate(prefab, parent, true):コピー元のワールド位置・回転を維持する
  • Instantiate(prefab, position, rotation, parent):指定したワールド位置・回転で生成し、親を付ける

なお、生成後に親を変更するSetParentのworldPositionStaysは、省略するとtrueです。Instantiateで親だけを指定した場合とは既定の扱いが違うので、置き換えるときは注意してください。

親オブジェクトを指定してUIを生成する具体例として、Scroll ViewのContentにTextを追加する方法も参考にしてください。

生成されない・位置がずれるときの確認ポイント

生成されない場合

  • Prefab欄がNoneになっていないか:ProjectビューのPrefabを割り当てます。親指定の例ではObj Parent欄も必要です
  • スクリプトをアタッチしているか:Spawnerとコンポーネントが有効か、Consoleにコンパイルエラーがないかを確認します。ファイル名とクラス名はPrefab_Instantiateにそろえます
  • Play中のHierarchyに生成物があるか:見つかる場合は、Prefabや親が非アクティブになっていないか、カメラの表示範囲外にないかを確認します

サンプルはStartで1回だけ生成します。Play中にPrefab欄を直しただけで再実行されるわけではないため、一度Playを止めてからInspectorの割り当てを修正し、もう一度再生しましょう。Play中に変更した設定は、停止時に元へ戻る点にも注意してください。

また、この記事のコードにUnityEditorのusingは不要です。UnityEditorはエディター専用で、プレイヤー向けのランタイムコードから参照できません。ビルド時にUnityEditorのエラーが出る場合は、以前のサンプルのusing static UnityEditor.PlayerSettings;が残っていないか確認してください。UnityEditorの公式説明に対応範囲が記載されています。

位置・回転・大きさが想定と違う場合

  • ワールド座標とローカル座標を混ぜていないか:Transform.positionはワールド座標、localPositionは親基準の座標です。親があるオブジェクトのInspectorのPositionはローカル座標になります
  • 親のRotationやScaleを確認したか:親の回転・拡大縮小も子に影響します。まず今回の準備と同じRotation(0, 0, 0)、Scale(1, 1, 1)で違いを確認します
  • UIの配置を自動で制御していないか:Layout Groupなどが付いていると、生成後の位置や大きさがレイアウト側で調整される場合があります

親子関係とInspectorの値はTransformの公式説明、UIの自動配置はAuto Layoutの公式説明も参考になります。

まとめ

Instantiateは、Prefabからゲーム中にオブジェクトを生成するための基本関数です。まずは次の3パターンを使い分けましょう。

  • Prefabだけを指定:コピー元の位置・回転で複製する。原点になるとは限らない
  • 位置と回転を指定:引数で指定したワールド位置・回転で生成する
  • 親を指定:指定したTransformの子として生成する。親だけの指定と、位置・回転も渡す指定では座標の扱いが異なる

まずはCubeで生成位置とHierarchyの変化を確認してから、敵やアイテム、UIの生成に応用してみてください。