Los tiradores y los juegos que usan sistemas de partículas tienen que crear, manipular y luego eliminar muchos objetos a la vez, tal vez incluso cientos por fotograma. Esto puede llevar al juego a retrasarse o incluso a congelarse. En este tutorial, veremos cómo conjuntos de objetos puede ayudar con este problema, al permitirnos reutilizar objetos en lugar de recrearlos desde cero.
Nota: Aunque este tutorial está escrito con Java, debería poder usar las mismas técnicas y conceptos en casi cualquier entorno de desarrollo de juegos.
Una ocurrencia común en los tiradores y sistemas de partículas es crear y eliminar muchos objetos en rápida sucesión. Desde disparar armas hasta lanzar hechizos mágicos, crear y eliminar los objetos necesarios puede ser una operación costosa. Cuando muchas de estas operaciones se realizan rápidamente, el juego puede retrasarse o congelarse.
La razón es que un programa de fondo llamado recolector de basura requiere recursos del sistema para limpiar la memoria utilizada. Es esta limpieza la que puede hacer que el sistema se retrase.
Una forma de evitar esto es usar un grupo de objetos para reutilizar objetos antiguos en lugar de eliminarlos.
Para comprender por qué se necesita un grupo de objetos, primero debemos entender cómo funciona la recolección de basura.
La recolección de basura es el proceso de gestión automática de recursos. Es responsable de liberar espacio en la memoria para reutilizarlo cuando ya no sea necesario..
Echa un vistazo al siguiente ejemplo de un simple para
lazo:
para (int i = 1; i < 10; i++) System.out.println(i);
Cuando un programa ejecuta este bucle, creará una variable yo
asignando suficiente memoria para contener los datos de la variable (en este caso, suficiente espacio para contener un número entero). Una vez que el bucle ha terminado, la variable yo
ya no es necesario; el programa eventualmente detectará esto y luego podrá liberar la memoria para otros usos.
En su mayor parte, la recolección de basura se realiza automáticamente y sin previo aviso. A veces, sin embargo, si se necesita liberar una gran cantidad de memoria de una vez, la recolección de basura puede obligar al programa a usar recursos valiosos del sistema para liberar la memoria necesaria. Esto puede hacer que el programa se retrase o se congele temporalmente, ya que esto lleva tiempo.
El sistema también puede demorarse cuando se necesita mucha memoria a la vez para crear nuevos objetos. Esto se debe a que la asignación de memoria puede ser tan intensiva en recursos como liberarla.
Debido a esto, es importante administrar la recolección de basura para que no interfiera con su programa.
Un grupo de objetos es una estructura de datos que reutiliza objetos antiguos para no crear o eliminar continuamente otros nuevos. En lugar de asignar una nueva memoria para un objeto y luego liberarla una vez que hayamos terminado con ella, seguimos reutilizando el objeto una y otra vez modificando sus valores. De esta manera, la memoria no tiene que liberarse, evitando así la recolección de basura.
El agrupamiento de recursos puede ofrecer un aumento significativo del rendimiento en situaciones donde el costo de inicializar una instancia de clase es alto, la tasa de creación de instancias de una clase es alta y el número de instancias en uso en un momento dado es bajo.
Piense en ello como una baraja de cartas donde la baraja representa la memoria. Cada vez que necesitas una nueva carta (es decir, necesitas un nuevo objeto), robas una de la baraja y la usas; Una vez que hayas terminado con la tarjeta, la arrojas a un bote de basura pequeño..
Eventualmente, se quedaría sin cartas y necesitaría un nuevo mazo, o el bote de basura se llenaría y sería necesario retirarlo (es decir, la recolección de basura). En cualquier caso, debe detener lo que está haciendo actualmente para obtener un nuevo mazo o sacar la basura.
En un grupo de objetos, cada carta del mazo está en blanco. Cuando necesita una tarjeta, escribe la información básica que necesita y la utiliza. Una vez que haya terminado con la tarjeta, borra la información y la vuelve a poner en la baraja. De esta manera, no se necesitan nuevas tarjetas y nunca tendrá que tirar una tarjeta en el bote de basura. Es la forma de reciclar del programador.!
Implementar un grupo de objetos no es demasiado difícil, pero como requiere que actúe un objeto, también le mostraré cómo implementar el objeto que contendrá el grupo de objetos. Dado que un conjunto de objetos funciona mejor en los objetos que necesitan crearse y eliminarse rápidamente, un sistema de partículas parece ser la opción más ideal. Es un dos por uno especial.!
Primero empezaremos implementando el Partícula
clase. El siguiente código está escrito en Java, pero se pueden usar las mismas técnicas para la mayoría de los otros lenguajes de programación. Voy a comentar después de cada fragmento de código.
public class Particle private int framesLeft; int int privado; privado int posY; int privado xVelocity; int yVelocity privado; / ** * Constructor * / public Particle () framesLeft = 0; posX = 0; posY = 0; xVelocity = 0; yVelocity = 0; / ** * Inicialice todas las variables antes de usar * / public void init (int pFramesLeft, int pPosX, int pPosY, int pXVelocity, int pYVelocity) framesLeft = pFramesLeft; posX = pPosX; posY = pPosY; xVelocity = pXVelocity; yVelocity = pYVelocity; / ** * Animar la partícula * / public boolean animate () if (isAlive ()) posX + = xVelocity; posY + = yVelocity; framesLeft--; // Dibuja el objeto en la pantalla devuelve falso; devuelve true; / ** * Determine si una partícula está viva (o en uso) * / public boolean isAlive () return framesLeft> 0;
Como puedes ver, una partícula es un objeto muy simple. Contiene algunas variables para realizar un seguimiento de dónde está en la pantalla (posx
y ramillete de flores
), que tan rápido va (xVelocity
y yVelocidad
) y cuántos cuadros debe dibujar (marcos dejados
). Una partícula está "viva" si aún tiene cuadros por dibujar, y "muerta" de lo contrario.
En cada cuadro, el animar
La función se llama para actualizar la posición de la partícula y dibujarla en la pantalla. Vuelve falso
Si la partícula sigue viva, de lo contrario, devuelve verdadero, lo que significa la partícula murió
.
Nota: El código para dibujar la partícula está fuera del alcance de este tutorial..
A continuación, implementaremos el ObjectPool
clase:
public class ObjectPool private int size; Lista privada de partículas; / ** * Constructor * / public ObjectPool (int pSize) size = pSize; partículas = nueva ArrayList (); // Inicializar la matriz con partículas para (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));
los ObjectPool
La clase es también un objeto relativamente simple. Solo contiene una lista de partículas y el tamaño de la lista. El poder del conjunto de objetos viene en sus dos métodos., obtener
y animar
.
Cuando la agrupación de objetos necesita obtener un nuevo objeto para su uso, examina el último elemento de la lista y verifica si está vivo o muerto. Si está vivo, la agrupación está llena, por lo que se debe crear un nuevo objeto; si está muerto, el grupo inicializa el último elemento de la lista, lo saca del final y lo empuja nuevamente al frente de la lista. De esta manera, el grupo siempre tiene objetos disponibles en la parte posterior y objetos usados en el frente.
En el animar
Método, si la función animada de la partícula regresa. cierto
, El objeto está listo para ser reutilizado. La agrupación elimina el elemento de la lista y lo empuja hacia atrás. Manipular la lista de esta manera hace que la creación y destrucción de objetos en la piscina sea constante y muy eficiente..
En este ejemplo, los objetos que el grupo de objetos mantendrá son partículas, pero para su propio grupo de objetos puede ser lo que desee. Mientras existan las mismas funciones en el objeto que usará como en la clase de Partícula, funcionará de la misma manera..
Equipado con un conjunto de objetos, es el momento de crear un sistema de partículas para crear un efecto brillante..
Comenzamos creando el conjunto de objetos para mantener todas las partículas en la pantalla..
ObjectPool pool = new ObjectPool (100);
En cada fotograma, generaremos una nueva partícula en el centro de la pantalla y le asignaremos una velocidad aleatoria. Por último, animaremos el conjunto de objetos..
Random randomGenerator = new Random (); int velX = randomGenerator.nextInt (5); int velY = randomGenerator.nextInt (5); pool.get (30, 200, 200, velX, velY); pool.animate ();
La creación y eliminación rápidas de objetos pueden hacer que un juego se retrase o se congele. Al utilizar un grupo de objetos, puede guardar los recursos del sistema y la frustración del usuario.