Unity

【Unity】pool化で処理速度改善【簡単】

pool化とは?

簡単に言うと、一度生成したPrefabを繰り返し再利用できる仕組みです

最初にも言いましたが
Unityでよく使うInstantiate()やDestroy()は実はかなり重い処理なので
この2つの処理をゲーム中に何度も呼ぶのは避けたいところです

そこでInstantiate()でのPrefabの生成は
ゲームが始まる前や、ゲームが始まった直後に全て実行しておいて

あとはSetActive()でPrefabの表示と非表示を切り替えることで
Instantiate()とDestroy()の代用をしちゃおうというのが今回紹介するpool化です!!

実際にpool化する

pool化の全体像

今回書いていくスクリプトはふたつです

Generatorスクリプト 空のGameObjectに貼って
Prefabの生成(Instantiate)と表示(SetActive(true))
に関する処理をかく
Prefabスクリプト 今回使うPrefabに貼って
Prefabの非表示(SetActive(false))
に関する処理を書く

ちなみになぜふたつに分けるのかというと
生成や表示するPrefabは現在非表示状態のものならどれでもいいのに対して
消去についてはplayerに踏まれた時などそれぞれ個別のPrefabが管理したほうがわかりやすいからです

コードを書いていく

Prefabスクリプト

Prefabスクリプト 今回使うPrefabに貼って
Prefabの非表示(SetActive(false))
に関する処理を書く
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PrefabScript : MonoBehaviour
{
    void Update()
    {
        if (条件)
        {   
            //使わなくなったタイミングで非表示にする
            this.gameObject.SetActive(false);
        }

    }
}

使わなくなったら非表示にする。それだけです。

Generatorスクリプト

Generatorスクリプト 空のGameObjectに貼って
Prefabの生成(Instantiate)と表示(SetActive(true))
に関する処理をかく

一見複雑ですがやっていることは簡単で
以下のふたつだけです

1.Start関数でPrefabを一気に生成して配列に格納しておきます
2.自作したReusePrefab()メソッドで非表示のものを指定した位置に表示する

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GeneratorScript : MonoBehaviour
{
    //PrefabとPrefabを格納する配列を宣言
    public GameObject myPrefab;
    private GameObject[] prefabArray = new GameObject[50];

    void Start()
    {
        //最初にInstantiateで全て生成してprefabArrayに格納しておく
        for(int i = 0; i < prefabArray.Length; i++)
        {
            GameObject prefab = Instantiate(this.myPrefab);
            //この時生成したprefabは一旦非表示状態にしておく
            prefab.SetActive(false);
            prefabArray[i] = prefab;
        }
    }

    void Update()
    {
        if(条件)
        {
            //好きなタイミングでprefabを表示させる
            //表示する位置を引数で指定してあげると便利(今回は2dゲームを想定してVector2で書いておく)
            Vector2 position = new Vector2(x座標,y座標)
            ReusePrefab(position);
        }
    }


    // Prefabの位置を指定して出現させるメソッド
    private void ReusePrefab(Vector2 position)
    {
        //現在非表示状態のprefabを探す
        for (int i = 0; i < prefabArray.Length; i++)
        {
            if (prefabArray[i].activeSelf == false)
            {
                //位置を指定して出現させる
                prefabArray[i].transform.position = position;
                prefabArray[i].SetActive(true);
                //一つでも見つけたらfor文を抜ける
                break;
            }
        }
    }
}

もちろんこれは非表示のprefabがひとつもないと何も表示しないので
最初に生成するprefabの数は考えられる最大数以上を生成しておきましょう

Prefabの最大数がわからない場合

ちなみに最大数がわからないよ!!という場合は
配列ではなくリストに格納して
非表示状態のprefabが足りないなら新しく生成してリストに追加する処理を書いてあげれば良いだけです

具体的にはGeneratorスクリプトを以下のように変更すれば良いでしょう

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GeneratorScript : MonoBehaviour
{
    public GameObject myPrefab;
    //ここを配列ではなくリストにする(変更)
  private List prefabList = new List();

    void Start()
    {
        //最初の生成は無しでいい(削除)
    }

    void Update()
    {
        if(条件)
        {
       //ここは同じ
            Vector2 position = new Vector2(x座標,y座標)
            ReusePrefab(position);
        }
    }


    // Prefabの位置を指定して出現させるメソッド
    private void ReusePrefab(Vector2 position)
    {
        //prefabが足りないか判定する変数(追加)
        bool isPrefabEnough = false;

        //prefabList.Count回繰り返すようにする(変更)
        for (int i = 0; i < prefabList.Count; i++)
        {
            if (prefabList[i].activeSelf == false)
            {
                prefabList[i].transform.position = position;
                prefabList[i].SetActive(true);
                //prefabが足りているからtrueにする(追加)
                isPrefabEnough = true;
                break;
            }
        }

        //もしもprefabが足りずbreakしなかった時の処理(追加)
        if(isPrefabEnough == false)
        {
            //生成
            GameObject prefab = Instantiate(this.myPrefab);
            //位置決める
       prefab.transform.position = position;
            //表示する
            prefab.SetActive(true);
            //格納しとく
            prefabList.Add(prefab);
        }
    }
}