Hasta ahora, logramos crear una sola partícula que hacemos renacer cada vez que muere. Ahora, queremos crear un flujo continuo de partículas, agregando una nueva con cada ciclo por medio de draw(). Podríamos simplemente crear un arreglo y empujar una nueva partícula en él cada vez:
var particles = [];
draw = function() {
  background(133, 173, 242);
  particles.push(new Particle(new PVector(width/2, 50)));

  for (var i = 0; i < particles.length; i++) {
    var p = particles[i];
    p.run();
  }
};
Si pruebas y ejecutas ese código por unos minutos, probablemente comenzarás a ver la velocidad de los cuadros de animación más y más lentos hasta que el programa se paralice. Eso es porque creamos más y más partículas que tenemos que procesar y deplegar, sin nunca quitar ninguna. Una vez que las partículas están muertas, son inútiles, así que bien podemos ahorrarle trabajo innecesario a nuestro programa y eliminar esas partículas.
Para quitar elementos de un arreglo en JavaScript, podemos usar el método splice(), especificando el índice deseado para eliminar y la cantidad a eliminar (solo uno). Haríamos eso después de consultar si la partícula en realidad está muerta:
var particles = [];
draw = function() {
  background(133, 173, 242);
  particles.push(new Particle(new PVector(width/2, 50)));

  for (var i = 0; i < particles.length; i++) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
};
Aunque el código anterior funcionará bien (y el programa nunca se paralizará), hemos abierto una caja de Pandora mediana. Cada vez que manipulamos el contenido de un arreglo mientras iteramos sobre ese mismo arreglo, podemos meternos en problemas. Toma, por ejemplo, el siguiente código:
for (var i = 0; i < particles.length; i++) {
  var p = particles[i];
  p.run();
  particles.push(new Particle(new PVector(width/2, 50)));
}
Este es un ejemplo algo extremo (con lógica errónea), pero prueba el punto. En el caso anterior, para cada partícula en el arreglo, le agregamos una nueva partícula al arreglo (así cambiando la propiedad length del arreglo). Esto resultará en un bucle infinito, ya que i nunca puede aumentar más allá de particles.length.
Mientras que quitar elementos del arreglo de partículas durante un bucle no causa que el programa se bloquee (como lo hace cuando le agregamos), el problema es casi más malicioso que no deja ninguna evidencia. Para descubrir el problema, primero debemos establecer un hecho importante. Cuando se elimina un elemento de un arreglo, todos los elementos son desplazados un lugar a la izquierda. Observa el siguiente diagrama, donde se elimina la partícula C (índice 2). Las partículas A y B mantienen el mismo índice, mientras que las partículas D y E cambian de 3 y 4 a 2 y 3, respectivamente.
Supongamos que somos i recorriendo el arreglo.
  • cuando i = 0 → revisar partícula A → no borrar
  • cuando i = 1 → revisar partícula B → no borrar
  • cuando i = 2 → revisar partícula C → ¡borrar!
  • (Desplazar a las partículas D y E de las posiciones 3 y 4 a las 2 y 3)
  • cuando i = 3 → revisar partícula E → no borrar
¿Te das cuenta del problema? ¡Nunca revisamos a la partícula D! Cuando C fue eliminada de la posición #2, D se movió a la posición #2, pero i ya se había movido a la posición #3. Esto no es un desastre, ya que la partícula D será revisada la próxima vez. Aún así, la expectativa es que estamos escribiendo código para iterar sobre cada elemento individual del arreglo. Saltarse un elemento es inaceptable.
Hay una solución sencilla para este problema: simplemente iterar hacia atrás sobre el arreglo. Si estás desplazando elementos de derecha a izquierda a medida que los elementos se quitan, es imposible omitir un elemento por accidente. Todo lo que tenemos que hacer es modificar las tres partes en el bucle for:

  for (var i = particles.length-1; i >= 0; i--) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
Juntándolo todo, tenemos esto:
Bien. Ya hicimos dos cosas. Escribimos un objeto para describir un Particle individual (partícula en inglés). Averiguamos cómo utilizar arreglos para manejar muchos objetos Particle (con la posibilidad de agregarlos y borrarlos a voluntad).
Podríamos parar aquí. Sin embargo, un paso adicional que podemos y debemos tomar, es crear un objeto para describir la propia colección de objetos Particle (partículas): el objeto ParticleSystem (sistema de partículas). Esto nos permitirá quitar la lógica bultosa de iterar sobre todas las partículas de la pestaña principal, así como abrir la posibilidad de tener más de un sistema de partículas.
Si recuerdas el objetivo que definimos al principio de este capítulo, queríamos que nuestro programa se pareciera a esto:
var ps = new ParticleSystem(new PVector(width/2, 50));

draw = function() {
  background(0, 0, 0);
  ps.run();
};
Tomemos el programa que escribimos arriba y veamos cómo encajaría en el objeto ParticleSystem.
Aquí está lo que teníamos antes. Observa las líneas en negritas:
var particles = [];

draw = function() {
  background(133, 173, 242);
  particles.push(new Particle(new PVector(width/2, 50)));

  for (var i = particles.length-1; i >= 0; i--) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
};
Aquí está cómo podemos reescribir eso en un objeto. Vamos a hacer que el arreglo de particles (partículas) sea una propiedad del objeto, hacer un método contenedor (wrapper method en inglés) addParticle para agregar nuevas partículas y poner toda la lógica de ejecutar la partícula en run (ejecutar):
var ParticleSystem = function() {
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function() {
  this.particles.push(new Particle());
};

ParticleSystem.prototype.run = function() {
  for (var i = this.particles.length-1; i >= 0; i--) {
      var p = this.particles[i];
      p.run();
      if (p.isDead()) {
        this.particles.splice(i, 1);
      }
    }
};
También podríamos agregar algunas nuevas características al propio sistema de partículas. Por ejemplo, sería útil para el objeto ParticleSystem llevar un seguimiento de un punto de origen de dónde se crean las partículas. Esto empata con la idea de que el sistema de partículas sea un “emisor”, un lugar donde nacen las partículas y de donde son enviadas al mundo. El punto de origen debería inicializarse en el constructor.
var ParticleSystem = function(position) {
  this.origin = position.get();
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function() {
  this.particles.push(new Particle(this.origin));
};
Aquí está todo junto: