今回はゲームオブジェクトのプーリングを行ってゲームオブジェクトを再利用するようにしたいと思います。
プーリングなんて難しい言葉のように聞こえますが、あらかじめ用意しておいたゲームオブジェクトを使うようにするという事です。
あらかじめ弾のインスタンスを生成しておき、数が足りている間はそのゲームオブジェクトを再利用します。
数が足りない場合は新たに弾をインスタンス化しプール数を増やします。
今回の記事は
で使用した物理的な弾を飛ばす機能を改造して作成していきます。
ShotTestスクリプトの修正
ShotTestスクリプトであらかじめ弾のプレハブをインスタンス化し非アクティブにしてリストに保持しておき、弾を発射した時はそのゲームオブジェクトの位置等を調整しアクティブにすることにします。
ShotTestスクリプトをShotBulletという名前に変更します(特に変えなくてもいいです)。
最初にフィールド部分とStartメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | using UnityEngine; using System.Collections; using System.Collections.Generic; public class ShotBullet : MonoBehaviour { // 弾のプレハブ [SerializeField] private GameObject bullet; // 弾を飛ばす力 [SerializeField] private float power = 500f; // 玉のオブジェクトを入れておくリスト private List<GameObject> bulletPoolObjs = new List<GameObject>(); // 最初にプーリングする数 [SerializeField] private int numOfPool = 30; private float elapsedTime = 0f; [SerializeField] private float waitTime = 0.1f; [SerializeField] private float offset = 0f; void Start() { // あらかじめ弾のゲームオブジェクトをインスタンス化 GameObject obj; for (int i = 0; i < numOfPool; i++) { obj = GameObject.Instantiate (bullet); obj.SetActive (false); bulletPoolObjs.Add (obj); } } |
リストで弾のプレハブをインスタンス化したものを保持するようにします。
numOfPoolはデフォルトのプーリングをしておく数です。
StartメソッドでnumOfPoolの数分だけ弾をインスタンス化し、非アクティブにし、リストに追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | // Update is called once per frame void Update () { elapsedTime += Time.deltaTime; if (elapsedTime < waitTime) { return; } if (Input.GetButton ("Fire1")) { // カメラのレンズの中心を求める var centerOfLens = Camera.main.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, Camera.main.nearClipPlane + offset)); // 弾に空きがあるかどうか bool isGetObject = false; for (int i = 0; i < bulletPoolObjs.Count; i++) { if (!bulletPoolObjs [i].activeSelf) { bulletPoolObjs [i].transform.position = centerOfLens; bulletPoolObjs [i].transform.rotation = transform.rotation; bulletPoolObjs [i].SetActive (true); isGetObject = true; break; } } // 空きがなければ追加 if (!isGetObject) { var obj = GameObject.Instantiate (bullet); obj.transform.position = centerOfLens; obj.transform.rotation = transform.rotation; bulletPoolObjs.Add (obj); } elapsedTime = 0f; } } |
Updateメソッドで弾を登録したリストから非アクティブの弾を探し、位置や角度を変更し、アクティブにします。
リストの中から非アクティブのものが見つからなかったら新たに弾をインスタンス化しリストに追加し、これを利用します。
BulletTestスクリプトの修正
BulletTestスクリプトはBulletに名前を変更します(変更しなくてもいいです)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | using UnityEngine; using System.Collections; public class Bullet : MonoBehaviour { [SerializeField] private float power = 50f; [SerializeField] private float deleteTime = 2f; private Rigidbody rigid; private Ray ray; void Awake() { // Rigidbodyを取得し速度を0に初期化 rigid = GetComponent <Rigidbody> (); } // 弾がアクティブになった時 void OnEnable() { rigid.velocity = Vector3.zero; // カメラからクリックした位置にレイを飛ばす ray = Camera.main.ScreenPointToRay (Input.mousePosition); rigid.AddForce (ray.direction * power, ForceMode.Force); // 弾を発射してから指定した時間が経過したら自動で非アクティブにする Invoke ("DisableBullet", deleteTime); } void OnCollisionEnter(Collision col) { if (col.gameObject.tag == "Enemy") { DisableBullet (); Destroy (col.gameObject); } } void DisableBullet() { gameObject.SetActive (false); } } |
AwakeメソッドでRigidbodyを取得します。
OnEnableメソッドでRigidbodyのvelocityをVector3.zeroで初期化します。
これはプーリングを行う場合、ゲームオブジェクトをアクティブ、非アクティブにする事で再利用する為、アクティブになった時に一旦Rigidbodyのvelocityを0にしないと前のRigidbodyのvelocityの値で移動してしまうからです。
プーリングを行う場合はDisableBulletで弾のゲームオブジェクトを非アクティブにします。
OnCollisionEnter内でも弾のゲームオブジェクトを非アクティブにします。
これで弾のインスタンスをプーリングして使用する事が出来ます。