キューを使ったプール
CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 38/50。
プールには予備のオブジェクトを保管する場所が必要です。C#にはそのためのコレクション、Queue<T>があります。Enqueueはアイテムを末尾に追加し、Dequeueは先頭のアイテムを取り出し、Countは待機中のアイテム数を示します。この水槽では0.3秒ごとに泡が1つ浮かび上がり、それぞれの泡は水面でプールに戻ります。
using System.Collections.Generic;
using UnityEngine;
public class BubblePool : MonoBehaviour
{
public GameObject bubblePrefab;
private Queue<GameObject> pool = new Queue<GameObject>();
private float timer;
void Update()
{
timer += Time.deltaTime;
if (timer >= 0.3f)
{
timer = 0f;
Get(new Vector3(Random.Range(-2f, 2f), 0f, 0f));
}
}
public GameObject Get(Vector3 position)
{
GameObject bubble;
if (pool.Count > 0)
{
bubble = pool.Dequeue();
}
else
{
bubble = Instantiate(bubblePrefab);
bubble.GetComponent<Bubble>().pool = this;
}
bubble.transform.position = position;
bubble.SetActive(true);
return bubble;
}
public void Return(GameObject bubble)
{
bubble.SetActive(false);
pool.Enqueue(bubble);
}
}// Bubble.cs、bubble プレハブにアタッチ
public BubblePool pool;
void Update()
{
transform.Translate(0f, 2f * Time.deltaTime, 0f);
if (transform.position.y > 5f) pool.Return(gameObject);
}GetはまずCountを確認します。空のキューに対してDequeueを呼び出すと、InvalidOperationExceptionがスローされるためです。その後に初めてInstantiateを呼び出します。また、poolフィールドを設定する必要があるのは新しい泡だけです。再利用される泡には、すでに設定されています。キューは、最も長く待っていた泡から順に取り出します。先入れ先出しです。水面に到達した泡はDestroyではなくReturnを呼び出し、シーン内で非アクティブな状態のまま、次のGetまで待機します。
GetはSetActive(true)を呼び出す前に泡を配置します。オブジェクトを有効にするとOnEnableがすぐに実行されるため、その中の処理が泡の最後に消えた位置ではなく、新しい位置を認識できるようにするためです。再利用されたオブジェクトが初期状態に戻る場所もここです。AwakeとStartは泡が作られたときに一度だけ実行され、OnEnableはGetのたびに実行されます。
チャレンジ
中級砂の上の足跡。矢印キーで Player を動かせる状態です。Player に付いている Trail.cs は、1 単位歩くごとに Get(position) を呼び出して足跡を残し、各 Footprint は life(1.5)秒間持続します。現在、Get は毎回新しい足跡をインスタンス化し、それぞれが自分自身を破棄します。これらをプールしましょう。
Trail.csでは、予備の足跡をQueue<GameObject>に保持します。Trail が作成する各足跡のtrailフィールドには、この Trail を設定する必要があります。- Start で、
prewarm(6)個の足跡を作成して無効にし、プールを満たします。これにより、最初の数歩では新しい足跡が作られません。 Get(position)は、キューに足跡があればそこから取り出し、空の場合にのみ新しい足跡を作成します。その後、足跡を配置して有効にします。Return(footprint)は足跡を無効にし、キューに戻します。Footprint.csでは、足跡の経過時間を数え、life秒後に破棄する代わりにtrail.Return(gameObject)で戻します。再利用された足跡は、再び 1.5 秒間持続します。
Play を押して、しばらく歩き回ってから、Check を押してください。
自分で試してみよう
using System.Collections.Generic;
using UnityEngine;
public class Trail : MonoBehaviour
{
public GameObject footprintPrefab;
public float step = 1f;
public int prewarm = 6;
private Vector3 lastDrop;
void Start()
{
lastDrop = transform.position;
// プールを事前生成した足跡で満たす
}
void Update()
{
if (Vector3.Distance(transform.position, lastDrop) >= step)
{
lastDrop = transform.position;
Get(new Vector3(transform.position.x, 0.02f, transform.position.z));
}
}
public GameObject Get(Vector3 position)
{
GameObject footprint = Instantiate(footprintPrefab, position, Quaternion.identity);
footprint.GetComponent<Footprint>().trail = this;
return footprint;
}
public void Return(GameObject footprint)
{
// 予備の足跡はプール内で待機する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。