あるオブジェクト(親)に対してInstantiateで子オブジェクトを任意の数生成したり、あるいはそのオブジェクトの子オブジェクトをまとめて消したりしたいケースは多い。
[ContextMenu("XXXX")]
はコンテキストメニューに"XXXX"の名前で新たに項目が追加されて自由にメソッドを実行できます。よく使います。
子オブジェクト量産する
void GenerateChildren() { for (int i = 0; i < _num; i++) { var parent = this.transform; var instance = Instantiate(_prefab, spawnPos(), Quaternion.identity, parent); } }
Instantiateの4つ目の引数にparentObj.transform
を与えるとそれが親になります。
あるいはSetParent()を使った書き方もあります。どちらが一般的なのでしょうか?ぐぐったら、一応そのパフォーマンスを測った記事があったので載せておきます。
ちなみに余談ですが、今日定時後にまさにこんな感じのスクリプトを書いてPR作ろうとしたら動作確認で不審な動きをして「ど、どうなってるんだあああああ!」って1時間くらい悩んでいたら、なんてことはないinstance.setData
的な処理をやろうとして _prefab.setData
とやってしまっていました。凡ミスですが、沼りました。助けてくれた先輩に感謝です。
子オブジェクト一括削除する
void DestroyAllChildren() { for(int i = 0; i < transform.childCount; i++) { Destroy(transform.GetChild(i).gameObject); } transform.DetachChildren(); }
ここではDestroyを使っていますが、実を言うとコンテキストメニューからのコマンド実行を最初から考えており、その際にedit mode(not play mode)でなんの気なしに実行したらエラーが出てしまい、読むと「edit modeでオブジェクトを削除したいんだったらDestroyImmediateを使って!」的なエラーメッセージが。
ということでそれにならってDestroyImmediateで書いてレビューお願いしたら先輩に「(今回みたいなケースならまあ使いたいのもわかるけど)非推奨だよ!」と教わったという経緯があります。
ヒエラルキー内のオブジェクトの操作をしたいときはplay modeで動作を確認する、これを肝に銘じます。
ちなみにDestroyはゲーム画面からオブジェクトを消去してくれますが実は裏では完全に削除されておらず、そのフレームの最後?あるいは次のフレームの頭?の処理で綺麗サッパリ消えるようです。(このあたりはUnity内のフローによるところなのでもう少し勉強が必要そうです。)
とはいえ、それがわかるとedit modeだと変な挙動を示す理由もわかります。
transform.DetachChildren();
のところに関しては以下の記事の説明が簡潔でわかりやすいです。
コンテキストメニューから操作しているので何のエビデンスにもならない動作確認GIFです。