Esperamos que te haya sido útil empezar con un escenario sencillo de un objeto que atrae a otro objeto y luego seguir con un objeto atrae a muchos objetos. Sin embargo, probablemente te encontrarás en una situación un poco más complicada: muchos objetos se atraen entre sí. En otras palabras, cada objeto en un sistema dado atrae a cualquier otro objeto en ese sistema (excepto a sí mismo).
Ya tenemos hecho prácticamente todo el trabajo. Consideremos un programa con un arreglo de objetos Mover:
var movers = [];

for (var i = 0; i < movers.length; i++) {
    movers[i] = new Mover(random(0.1, 2), random(width), random(height));
}

draw = function() {
    background(255, 255, 255);
    for (var i = 0; i < movers.length; i++) {
        movers[i].update();
        movers[i].display();
    }
};
La función draw() es donde tenemos que hacer algo de magia. Actualmente estamos diciendo: “para cada mover i, actualízate y despliégate”. Ahora lo que necesitamos decir es: “para cada mover i, sé atraído por cualquier otro mover j, actualízate y despliégate”.
for (var i = 0; i < movers.length; i++) {
    // Para cada Mover, ¡revisar cada Mover!
    for (var j = 0; j < movers.length; j++) {
        var force = movers[j].calculateAttraction(movers[i]);
        movers[i].applyForce(force);
    }

    movers[i].update();
    movers[i].display();
}
En el ejemplo anterior, teníamos un objeto Attractor con un método llamado calculateAttraction(). Ahora, como tenemos movers que atraen movers, lo que tenemos que hacer es copiar ese método en el objeto Mover.
Mover.prototype.calculateAttraction = function(m) {
  var force = PVector.sub(this.position, m.position);
  var distance = force.mag();
  distance = constrain(distance, 5.0, 25.0);                        
  force.normalize();

  var strength = (G * this.mass * m.mass) / (distance * distance);
  force.mult(strength);
  return force;
};
Por supuesto, tenemos un pequeño problema. Cuando estamos buscando cualquier mover i y cualquier mover j, ¿estamos bien con las veces que i es igual a j? Por ejemplo, ¿el mover #3 debería atraer al mover #3? La respuesta, por supuesto, es no. Si hay cinco objetos, solo queremos que el mover #3 atraiga al 0, 1, 2 y 4, saltándose a sí mismo. Sin embargo, queremos calcular y aplicar tanto la fuerza del mover #3 sobre el mover #1, como la del mover #1 sobre el mover #3. Las fuerzas calculadas serán las mismas para el par, pero la aceleración resultante será distinta, dependiendo de la masa de cada mover. Nuestra tabla de atracción debe verse así:
0 ⇢ 1, 2, 3, 4
1 ⇢ 0, 2, 3, 4
2 ⇢ 0, 1, 3, 4
3 ⇢ 0, 1, 2, 4
Y así, terminamos este ejemplo al modificar nuestro bucle de manera que los bucles internos eviten que los movers se atraigan a sí mismos:
for (var i = 0; i < movers.length; i++) {
    for (var j = 0; j < movers.length; j++) {
       if (i !== j) {
         var force = movers[j].calculateAttraction(movers[i]);
         movers[i].applyForce(force);
       }
    }

    movers[i].update();
    movers[i].display();
}
Ahora veamos todo junto:

Este curso de "Simulaciones Naturales" es un derivado de "La Naturaleza del Código" por Daniel Shiffman, usado bajo una Licencia Creative Commons Reconocimiento-NoComercial 3.0 Unported.