Unityでオブジェクトプールを利用して大量に使うオブジェクトの再利用

シューティングゲームを作っている時、弾を発射するときに生成(Instantiate)したり、被弾・画面外に出てしまったら破壊(Destroy)したりしていませんか?
そんなときはオブジェクトを生成・破壊を繰り返すのではなく、必要な量だけ最初に生成しゲーム中はそれを使い回すという方法を取ったりします。
それがオブジェクトプールと呼ばれる手法です。
今回はそれを実装してみたいと思います。

InstantiateやDestroyの処理はUnityではよく使われますが、それらの処理は重いと言われています。
少し前の記事ですが処理の速度を計算してくれている方がいました。
こちらですが見てみるとやはり時間がかかっています。

オブジェクトプールを使って少しでもゲームを軽くしていきましょう。

ちなみにこの処理を実装して作ったゲームはこちらになります。

またこの技術を使ったシューティングゲームの詳しい講座はこちらです。
この講座ではオブジェクトプール以外にも弾のパターンの作り方や、CSVをつかったステージの作り方など、ゲームづくりに役に立つ技を紹介してくれています。

Unityスキルアップ、
始めるなら今

パズル、脱出、RPG...目標のゲームを完成させよう!

人気のUnity講座はこちら

Udemy講座

オブジェクトプールの処理の流れ

前置きが長くなりましたが具体的にどういう処理をするのかを考えてみます。

  1. ゲーム開始時に親オブジェクトで必要な数だけ子オブジェクト(弾など)を画面外生成する
  2. 子オブジェクトを非表示にしておく
  3. 使いたいオブジェクト(Playerなど)から呼び出す
  4. 呼び出されたら親オブジェクトから子オブジェクトを貸し出す
  5. 使い終わったら回収し、再度非表示にする

この様な処理の流れになるかと思います。
では実際にこの仕組を作っていきましょう。

必要なオブジェクトの準備

それではUnityの新しい2Dプロジェクトを作りやっていきます。

必要となるゲームオブジェクトを作ります。
最低限これだけあればよいかと思います。

  1. 弾となるオブジェクト
  2. オブジェクトプール用の空オブジェクト
  3. 弾を呼び出すオブジェクト

現在この様な感じになっています。
白い丸がBulletで緑の四角がPlayerです。
オブジェクトプールの事前準備

ObjectPoolは空のゲームオブジェクトです。Positionはすべて0です。

弾のPrefab作成

次にBulletが移動していく処理を作成します。
BulletControllerというC#ファイルを作成しBulletにアタッチします。

中身についてはこのようにしておきます。

BulletのInspectorからSpeedを設定してあげましょう。
これで弾は上に移動していきます。
画面外に出たら回収する処理や、表示、回収の処理は後に記述していきます。
この段階でBulletをPrefab化してHierarchyから削除しておきます。

ObjectPoolの作成

次にObjectPoolを作っていきましょう。
ObjectPoolControllerというC#スクリプトを作成しHierarchy上のObjectPoolにアタッチします。
中身はこの様な感じにしました。

まず必要な変数を用意します。
そしてAwake関数でゲーム開始直後にQueueの初期化と弾Prefabの生成を行います。
ちなみになぜ生成時に画面外に配置するかというと、一瞬弾がゲーム上に表示されてしまう可能性があるからsetPosで画面外の座標を指定しています。

Launch関数ではVector3でポジションを受け取り、弾を渡します。
Collect関数では弾を回収して非表示にし、Queueに再度追加しています。

続いて先程作ったBulletController側に処理を書いていきます。

まず親のオブジェクトであるObjectPoolControllerを取得します。
続いてOnBecameInvisible、ShowInStage、HideFromStageの中身を記述しています。

この状態で一度ゲームを起動させてみると下のようになりました。
オブジェクトプールの確認
ObjectPoolの子要素としてBulletが非表示で生成されているのがわかると思います。
今回は100個生成しています。

Playerの作成

最後にPlayerから生成したBulletを呼び出してみます。
LauncherというC#スクリプトを作成しPlayerにアタッチします。

今回は特に「スペースキーを押したら発射」などではなくシンプルに開始時に発射するようにしてあります。
PlayerのInspectorから間隔を設定し起動してみましょう。
今回Intervalは0.3にしてみました
コルーチンによるオブジェクトプール再利用

弾がプレイヤーの位置に渡され発射され、Hierarchyで順番に表示され画面外に出たら非表示になっているのが確認できるかと思います。

今回はPlayerの移動だったり弾が何かにあたった処理は実装していませんが、このようにしてオブジェクトを再利用することでInstantiateやDestroyを使う回数を減らしゲームを軽くすることができるようになります。
またオブジェクトプールは弾以外にも色々と使い道があると思いますので、大量のオブジェクトを使うことがある時は是非使ってみてください。

関連記事

最後までご覧頂いてありがとうございました。

セール中!
C#プログラミング入門

もっと早く教えてほしかった!

Unity C#プログラミング入門