マルチシーンを使った開発で Instantiate を呼ぶと、思いもしないシーンにInstantiateしてしまう話


マルチシーンを使った開発

Unity 5 系のいつからから、シーンを複数呼ぶことができるようになりました。
現在のプロジェクトで初めてマルチシーンを使用しています。
そのときにハマった罠を紹介できればと思います。

Instantiate を呼ぶと、どのシーンに配置される?

Unity を使ってる人ならみんな大好き(?) Instantiate。
GameObject を hierarchy 上で生成するときに使いますよね。
マルチシーンがないときには何も意識せずに Instantiate したら、シーン上に GameObject が生成されました。

さて、マルチシーンで Instantiate したら、どのシーンに GameObject が作られるのでしょうか?

Instantiate シーンを単独で開いて GameObject の作成

Instantiate シーンを開いて、適当な Prefab(Cube) を Instantiate しました。
ボタンの Addlistener に Instantiate するだけですね。

[SerializeField] private Button _instantiatePrefabButton;

[SerializeField] private GameObject _prefab;

// Use this for initialization
private void Start()
{
    _instantiatePrefabButton.onClick.AddListener(() => { Instantiate(_prefab); });
}

まぁ、シーンは一つしかないので、そのシーンに配置されますね。

Instantiate シーンを Additive で追加する形で開いて GameObject を作成

最初に適当なシーン(ここでは Main)を開いて、そのあとに Instantiate シーンを Additive で開いてみます。

[SerializeField] private Button _addSceneButton;

private void Start()
{
    addSceneButton.onClick.AddListener(() =>
           SceneManager.LoadScene("Instantiate", LoadSceneMode.Additive));
}

さて、Instantiate シーンで Instantiate する GameObject は、一体どのシーンに作られるのでしょうか

Instantiate シーンに作られなくて、Main シーンに作られてしまいました。

対策(?)

Instantiate シーンに、適当な空の GameObject を作成し、それを親にして GameObject を作成しましょう。

private void Start()
{
    _instantiatePrefabButton.onClick.AddListener(() => { Instantiate(_prefab, _transform); });
}

Instantiate シーンに GameObject が作成されましたね。

まとめ

マルチシーンを使用するときには、Instantiate される Hierarchy 上の場所にも気をつけましょう。

たとえば上記の例で Instantiate シーンを Unload しても、本来 Instantiate シーンで作成した GameObject が消されないで残ってしまいます。(実際それでバグを産んだ)