Menu
CoddyTech

キューを使ったプール

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のたびに実行されます。

challenge icon

チャレンジ

中級

砂の上の足跡。矢印キーで 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)
    {
        // 予備の足跡はプール内で待機する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Unityにおけるゲームアーキテクチャのすべてのレッスン