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.
Aufgabe
MittelFuß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.csdie übrigen Fußabdrücke in einerQueue<GameObject>auf. Für jeden Fußabdruck, den der Trail erstellt, muss sein Feldtrailauf 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.cszählt ein Fußabdruck sein Alter und kehrt nachlifeSekunden mittrail.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
}
}
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
1Komponenten statt Hierarchien
Kleine KomponentenEin Basisskript für GegnerAbstrakte KomponentenKomponenten im ZusammenspielRückblick: Modularer Geschützturm4Serialisierte Daten
Serialisierbare KlassenListen im InspectorEnums im InspectorRückblick: Loot-Tabelle7Zustandsautomaten
Zustände als KlassenEin ZustandsautomatÜbergängeGegner-KIWiederholung: Türzustände10Projekt: Arena-Überlebenskampf
Der HeldGegnertypen2Interfaces in Unity
IDamageableInterfaces und TryGetComponentGetComponentsRückblick: Interaktionstaste5ScriptableObjects
Daten-AssetsWaffenwerteGemeinsame EinstellungenWellen als DatenRückblick: Item-Datenbank8Wiederverwendbarer Code
ErweiterungsmethodenEin generisches SingletonGenerische HilfsmethodenRückblick: FindNearest3Ereignisse
C#-Events in UnityIn OnEnable abonnierenUnityEvent-FelderEvents steuern die UIRückblick: Achievement-Popup9Objekt-Pooling
Warum Objekte poolenEin Pool mit einer WarteschlangeUnitys ObjectPoolRückblick: Geschoss-Pool