Un pool avec une file
Fait partie de la section Architecture de jeu dans Unity du Journey Unity de Coddy. Leçon 38 sur 50.
Un pool a besoin d’un endroit où garder ses objets de réserve, et C# fournit la collection adaptée : Queue<T>. Enqueue ajoute un élément à la fin, Dequeue prend celui qui se trouve au début, et Count indique combien attendent. Cet aquarium fait apparaître une bulle toutes les 0,3 seconde, et chaque bulle retourne dans le pool à la surface :
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, sur le préfabriqué de la bulle
public BubblePool pool;
void Update()
{
transform.Translate(0f, 2f * Time.deltaTime, 0f);
if (transform.position.y > 5f) pool.Return(gameObject);
}Get vérifie d’abord Count, car appeler Dequeue sur une file vide déclenche une InvalidOperationException. Ce n’est qu’ensuite qu’il appelle Instantiate, et seule une nouvelle bulle a besoin que son champ pool soit défini : une bulle réutilisée l’a déjà. La file fournit d’abord la bulle qui a attendu le plus longtemps : premier entré, premier sorti. Une bulle à la surface appelle Return au lieu de Destroy et reste dans la scène, inactive, jusqu’au prochain Get.
Get place la bulle avant SetActive(true), car son activation exécute immédiatement OnEnable, et tout ce qui s’y trouve doit voir la nouvelle position, et non celle où la bulle a disparu la fois précédente. C’est aussi là qu’un objet réutilisé recommence : Awake et Start ne se sont exécutées qu’une fois, à la création de la bulle, tandis que OnEnable s’exécute à chaque Get.
Défi
MoyenDes empreintes de pas dans le sable. Les touches fléchées déplacent le Player (prêt). Trail.cs, attaché au Player, dépose une empreinte tous les 1 unité parcourue en appelant Get(position), et chaque Footprint dure life (1.5) secondes. Actuellement, Get instancie une nouvelle empreinte à chaque fois, et chacune se détruit elle-même. Réutilise-les grâce à un pool :
- Dans
Trail.cs, conserve les empreintes disponibles dans uneQueue<GameObject>. Le champtrailde chaque empreinte créée par le Trail doit être défini sur ce Trail. - Dans Start, remplis le pool avec
prewarm(6) empreintes créées et désactivées, afin que les premiers pas n'en créent pas de nouvelles. Get(position)prend une empreinte dans la file s'il y en a une et n'en crée une nouvelle que si la file est vide ; il place ensuite l'empreinte et l'active.Return(footprint)désactive l'empreinte et la remet dans la file.- Dans
Footprint.cs, une empreinte compte son âge et, aprèslifesecondes, retourne au pool avectrail.Return(gameObject)au lieu d'être détruite. Une empreinte réutilisée dure de nouveau ses 1.5 secondes complètes.
Appuie sur Play, promène-toi un moment, puis clique sur Check.
Essayez vous-même
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;
// Remplir le pool avec des empreintes préparées à l’avance
}
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)
{
// Les empreintes de réserve attendent dans le pool
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Architecture de jeu dans Unity
1Des composants, pas des hiérarchies
Des composants simplesUn script de base pour les ennemisDes composants abstraitsDes composants qui fonctionnent ensembleRécapitulatif : tourelle modulaire4Données sérialisées
Classes sérialisablesListes dans l’inspecteurÉnumérations dans l’inspecteurRécapitulatif : table de butin7Machines à états
Les états sous forme de classesUne machine à étatsTransitionsLes cerveaux des ennemisRécapitulatif : états d’une porte10Projet : Survivant de l’arène
Le hérosTypes d’ennemis2Interfaces dans Unity
IDamageableInterfaces et TryGetComponentGetComponentsRécapitulatif : touche d’interaction5ScriptableObjects
Assets de donnéesStatistiques des armesParamètres partagésLes vagues sous forme de donnéesRécapitulatif : base de données d’objets3Événements
Événements C# dans UnityS’abonner dans OnEnableChamps UnityEventLes événements pilotent l’interface utilisateurRécapitulatif : fenêtre contextuelle de succès6Sauvegarder avec JSON
JsonUtilitySauvegarder le jeuCharger et valeurs par défautRécapitulatif : emplacements de sauvegarde9Réutilisation des objets
Pourquoi mettre les objets en poolUn pool avec une fileObjectPool de UnityRécapitulatif : pool de projectiles