Les tireurs et les jeux utilisant des systèmes de particules doivent créer, manipuler puis supprimer plusieurs objets à la fois, voire des centaines par image. Cela peut entraîner un jeu en retard ou même un blocage du jeu. Dans ce tutoriel, nous verrons comment pools d'objets peut aider à résoudre ce problème en nous permettant de réutiliser des objets au lieu de les recréer à partir de zéro.
Remarque: Bien que ce tutoriel ait été écrit en Java, vous devriez pouvoir utiliser les mêmes techniques et concepts dans presque tous les environnements de développement de jeux..
Un phénomène courant dans les systèmes de tir et de particules consiste à créer et à supprimer plusieurs objets en succession rapide. Que ce soit pour tirer avec des armes ou lancer des sorts magiques, créer et supprimer les objets nécessaires peut être une opération coûteuse. Lorsque beaucoup de ces opérations sont effectuées rapidement, le jeu risque de ralentir ou de geler..
La raison en est qu’un programme d’arrière-plan appelé Éboueur nécessite des ressources système pour nettoyer la mémoire utilisée. C’est ce nettoyage qui peut entraîner un ralentissement du système.
Une façon d'éviter cela consiste à utiliser un pool d'objets pour réutiliser d'anciens objets au lieu de les supprimer..
Pour comprendre pourquoi un pool d'objets est nécessaire, nous devons d'abord comprendre le fonctionnement de la récupération de place.
Le ramassage des ordures est le processus de gestion automatique des ressources. Il est responsable de libérer de la mémoire pour la réutiliser lorsqu'elle n'est plus nécessaire..
Jetez un oeil à l'exemple suivant d'un simple pour
boucle:
pour (int i = 1; i < 10; i++) System.out.println(i);
Quand un programme exécute cette boucle, il créera une variable je
en affectant suffisamment de mémoire pour contenir les données de la variable (dans ce cas, suffisamment d'espace pour contenir un entier). Une fois la boucle terminée, la variable je
n'est plus nécessaire; le programme finira par le détecter et pourra ensuite libérer de la mémoire pour d'autres utilisations.
La plupart du temps, la collecte des ordures s'effectue automatiquement et sans préavis. Parfois, cependant, si une grande quantité de mémoire doit être libérée en une seule fois, la récupération de place peut obliger le programme à utiliser des ressources système précieuses pour libérer la mémoire nécessaire. Cela peut entraîner un ralentissement ou un gel temporaire du programme, car cela prend du temps..
Le système peut également perdre du temps lorsqu'il faut beaucoup de mémoire en même temps pour créer de nouveaux objets. En effet, l’affectation de mémoire peut nécessiter autant de ressources que sa libération..
Pour cette raison, il devient important de gérer la récupération de place pour qu'elle n'interfère pas avec votre programme..
Un pool d'objets est une structure de données qui réutilise les anciens objets pour ne pas en créer ou en supprimer de nouveaux. Au lieu d'attribuer une nouvelle mémoire à un objet, puis de le libérer une fois que nous en avons terminé, nous continuons simplement à le réutiliser encore et encore en modifiant ses valeurs. De cette façon, la mémoire ne doit pas être libérée, évitant ainsi le garbage collection.
La mise en commun des ressources peut améliorer considérablement les performances dans les situations où le coût d'initialisation d'une instance de classe est élevé, le taux d'instanciation d'une classe est élevé et le nombre d'instances utilisées simultanément est faible..
Pensez-y comme à un jeu de cartes où le jeu représente la mémoire. Chaque fois que vous avez besoin d’une nouvelle carte (c’est-à-dire que vous avez besoin d’un nouvel objet), vous en piochez une et vous l’utilisez; une fois que vous avez terminé avec la carte, vous la jetez dans une petite poubelle.
Finalement, vous manquerez de cartes et aurez besoin d’un nouveau jeu, ou la poubelle deviendra pleine et devra être retirée (c’est-à-dire un ramassage des ordures). Dans les deux cas, vous devez arrêter ce que vous faites actuellement pour obtenir un nouveau deck ou pour sortir la corbeille..
Dans un pool d'objets, chaque carte du paquet est vide. Lorsque vous avez besoin d'une carte, vous écrivez les informations de base dont vous avez besoin et vous l'utilisez. Une fois que vous avez fini avec la carte, vous effacez les informations et vous les remettez dans le paquet. De cette façon, aucune nouvelle carte n'est nécessaire et vous ne devez jamais jeter une carte à la poubelle. C'est le moyen de recyclage du programmeur!
Implémenter un pool d'objets n'est pas trop difficile, mais comme cela nécessite un objet sur lequel agir, je vous montrerai également comment implémenter l'objet que le pool d'objets contiendra. Dans la mesure où un pool d'objets fonctionne mieux sur des objets devant être créés et supprimés rapidement, un système de particules semble être le choix idéal. C'est un spécial deux pour un!
Nous allons commencer par mettre en œuvre le Particule
classe. Le code suivant est écrit en Java, mais les mêmes techniques peuvent être utilisées pour la plupart des autres langages de programmation. Je vais commenter après chaque extrait de code.
Classe publique Particle private int framesLeft; privé int posX; int privé int; private int xVelocity; privé int yVelocity; / ** * Constructeur * / public Particle () framesLeft = 0; posX = 0; posY = 0; xVelocity = 0; yVelocity = 0; / ** * Initialise toutes les variables avant utilisation * / public void init (int pFramesLeft, int pPosX, int pPosY, int pXVelocity, int pYVelocity) framesLeft = pFramesLeft; posX = pPosX; posY = pPosY; xVelocity = pXVelocity; yVelocity = pYVelocity; / ** * Animer la particule * / public boolean animate () if (isAlive ()) posX + = xVelocity; posY + = yVelocity; cadresLeft--; // Dessine l'objet à l'écran return false; return true; / ** * Déterminer si une particule est vivante (ou en cours d'utilisation) * / public boolean isAlive () return framesLeft> 0;
Comme vous pouvez le constater, une particule est un objet très simple. Il contient quelques variables pour savoir où il se trouve à l’écran (posX
et posy
), à quelle vitesse ça va (xVelocity
et yVelocity
) et combien de vues il doit être dessiné (cadresGauche
). Une particule est «vivante» s'il lui reste des images à dessiner et «morte» sinon.
A chaque image, le animer
La fonction est appelée pour mettre à jour la position de la particule et la dessiner à l'écran. Il retourne faux
si la particule est toujours en vie, sinon elle retourne true, signifiant la particule décédés
.
Remarque: Le code pour dessiner la particule dépasse le cadre de ce tutoriel.
Ensuite, nous allons implémenter le ObjectPool
classe:
Classe publique ObjectPool private int size; particules privées de la liste; / ** * Constructeur * / public ObjectPool (int pSize) taille = pSize; particules = new ArrayList (); // Initialise le tableau avec des particules pour (int i = 0; i < size; i++) particles.add(new Particle()); /** * Get the first available particle and assign it the new values */ public void get(int pFramesLeft, int pPosX, int pPosY, int pXVelocity, int pYVelocity) if (!particles.get(size-1).isAlive()) particles.get(size-1).init(pFramesLeft, pPosX, pPosY, pXVelocity, pYVelocity); particles.add(0, particles.remove(size-1)); /** * Animate the object pool. Any dead particles will be placed at the front of the list to be reused */ public void animate() for (int i = 0; i < size; i++) if (particles.get(i).animate()) particles.add(size-1, particles.remove(i));
le ObjectPool
La classe est aussi un objet relativement simple. Il ne contient qu'une liste de particules et la taille de la liste. La puissance du pool d'objets vient de ses deux méthodes, obtenir
et animer
.
Lorsque le pool d'objets doit obtenir un nouvel objet à utiliser, il examine le dernier élément de la liste et vérifie s'il est actuellement actif ou mort. S'il est actif, le pool est plein et un nouvel objet doit donc être créé. s'il est mort, le pool initialise le dernier élément de la liste, l'affiche à la fin et le repasse au début de la liste. De cette façon, le pool a toujours des objets disponibles à l'arrière et des objets utilisés à l'avant.
dans le animer
méthode, si la fonction animate de la particule retourne vrai
, l'objet est prêt à être réutilisé. Le pool supprime l'élément de la liste et le pousse à l'arrière. Manipuler la liste de cette façon rend la création et la destruction d'objets dans le pool constantes et très efficaces.
Dans cet exemple, les objets que le pool d'objets contiendra sont des particules, mais pour votre propre pool d'objets, il peut s'agir de ce que vous voulez. Tant que vous utiliserez les mêmes fonctions que dans la classe Particle, elles fonctionneront de la même manière..
Équipé d'un pool d'objets, il est temps de créer un système de particules pour créer un effet sparkler.
Nous commençons par créer le pool d'objets pour contenir toutes les particules à l'écran.
ObjectPool pool = new ObjectPool (100);
À chaque image, nous allons générer une nouvelle particule au centre de l'écran et lui attribuer une vitesse aléatoire. Enfin, nous allons animer le pool d'objets.
Random randomGenerator = new Random (); int velX = randomGenerator.nextInt (5); int velY = randomGenerator.nextInt (5); pool.get (30, 200, 200, velX, velY); pool.animate ();
Créer et supprimer rapidement des objets peut potentiellement retarder ou geler un jeu. En utilisant un pool d'objets, vous pouvez économiser les ressources système et la frustration des utilisateurs..