Menu
CoddyTech

Ein Pool mit einer Warteschlange

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 38 von 50.

Ein Pool braucht einen Ort, an dem er seine Ersatzobjekte aufbewahren kann, und C# hat dafür die Sammlung Queue<T>: Enqueue fügt hinten ein Element hinzu, Dequeue nimmt das vorderste heraus, und Count gibt an, wie viele warten. Dieses Aquarium lässt alle 0.3 Sekunden eine Blase aufsteigen, und jede Blase kehrt an der Wasseroberfläche in den Pool zurück:

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, auf dem Blasen-Prefab
public BubblePool pool;

void Update()
{
    transform.Translate(0f, 2f * Time.deltaTime, 0f);
    if (transform.position.y > 5f) pool.Return(gameObject);
}

Get prüft zuerst Count, denn Dequeue löst bei einer leeren Warteschlange eine InvalidOperationException aus. Erst dann wird Instantiate aufgerufen, und nur bei einer neuen Blase muss das Feld pool gesetzt werden: Eine wiederverwendete Blase hat den Wert noch. Die Warteschlange gibt zuerst die Blase aus, die am längsten gewartet hat: zuerst hinein, zuerst hinaus. Eine Blase an der Wasseroberfläche ruft Return statt Destroy auf und bleibt in der Szene inaktiv, bis das nächste Get aufgerufen wird.

Get setzt die Position der Blase vor SetActive(true), denn beim Aktivieren wird sofort OnEnable ausgeführt, und alles, was dort passiert, sollte die neue Position sehen, nicht die Stelle, an der die Blase zuletzt verschwunden ist. Dort beginnt auch ein wiederverwendetes Objekt von vorn: Awake und Start wurden einmal ausgeführt, als die Blase erstellt wurde, und OnEnable wird bei jedem Get ausgeführt.

challenge icon

Aufgabe

Mittel

Fußspuren im Sand. Die Pfeile bewegen den Player (bereit). Trail.cs auf dem Player legt nach jeder gelaufenen Einheit einen Fußabdruck ab, indem es Get(position) aufruft, und jeder Footprint bleibt life (1.5) Sekunden bestehen. Heute erstellt Get jedes Mal einen neuen Fußabdruck, und jeder zerstört sich selbst. Verwende einen Pool:

  • Bewahre in Trail.cs die übrigen Fußabdrücke in einer Queue<GameObject> auf. Für jeden Fußabdruck, den der Trail erstellt, muss sein Feld trail auf diesen Trail gesetzt werden.
  • Fülle den Pool in Start mit prewarm (6) Fußabdrücken, die erstellt und deaktiviert werden, damit die ersten Schritte nichts Neues erstellen.
  • Get(position) nimmt einen Fußabdruck aus der Warteschlange, wenn einer vorhanden ist, und erstellt nur dann einen neuen, wenn sie leer ist; anschließend platziert es den Fußabdruck und aktiviert ihn.
  • Return(footprint) deaktiviert den Fußabdruck und legt ihn in die Warteschlange.
  • In Footprint.cs zählt ein Fußabdruck sein Alter und kehrt nach life Sekunden mit trail.Return(gameObject) zurück, statt zerstört zu werden. Ein wiederverwendeter Fußabdruck bleibt erneut die vollen 1.5 Sekunden bestehen.

Drücke Play, laufe eine Weile herum und klicke dann auf Check.

Probier es selbst

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;
        // Fülle den Pool mit vorab erzeugten Fußabdrücken
    }

    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)
    {
        // Übrige Fußabdrücke warten im Pool
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Spielarchitektur in Unity