オブジェクトプールを使ってちょっぴり負荷を軽減させる
オブジェクトプールってなんぞ
一時的なオブジェクトにオブジェクトプールを使うと、オブジェクトを作成し破棄するよりも時間がかかりません。なぜなら、メモリ割り当てが簡易になり動的メモリの割り当てのオーバーヘッドとガベージコレクション作業を削減できるからです。
スクリプトの最適化 - Unity マニュアル
毎回オブジェクトをInsantiateで生成して不要になったらDestoryとすると、特にシューティングゲームのようなものだと処理が重くなりがち。じゃあ破棄するんじゃなくて一旦SetActive(false)にして保管して使いまわそうというものらしい
こんな感じにしたい
あらかじめいくつかBulletを生成して、必要になったらSetActive(true)にしています。Bulletが画面外に出たらSetActive(false)で再利用。
作るにあたってこちらの記事を参考にさせていただきました。
megumisoft.hatenablog.com
Bullet.cs
public class Bullet : MonoBehaviour { void Update() { // 移動処理 } private void OnBecameInvisible() { gameObject.SetActive(false); } }
OnBecameInvisible()はカメラの画面外に出たら一度だけ呼ばれるメソッドです。ここでSetActive(false)しています。
ちなみにOnBecameInvisibleはGameViewだけでなくSceneViewの表示範囲にも映ってると呼ばれないのでデバック時には注意
PlayerShoot.cs
public class PlayerShoot : MonoBehaviour { [SerializeField] private GameObject bulletPrefab; [SerializeField] private Transform instPos; private List<GameObject> list_Bullets = new List<GameObject>(); const int MAX_COUNT = 10; void Start() { GameObject bullet; // あらかじめプールしておく for(int i = 0; i < MAX_COUNT; i++) { bullet = Instantiate(bulletPrefab); bullet.transform.parent = this.transform; bullet.gameObject.SetActive(false); list_Bullets.Add(bullet); } } void Update() { if(Input.GetMouseButtonDown(0)) { BulletShoot(); } } void BulletShoot() { for(int i = 0; i < list_Bullets.Count; i++) { if(!list_Bullets[i].gameObject.activeSelf) { list_Bullets[i].SetActive(true); list_Bullets[i].transform.position = instPos.position; return; } } } }
start()内であらかじめ生成しておき、SetActive(true)にして射出位置に移動させています。
ヒエラルキーのBulletがオンオフになってるのがわかります。今回のようなゲームではさほど恩恵は無さそうですが、弾幕があるシューティングゲームではほぼ必須の要素なので積極的に使って行きたいですね。