34.1 Separar estado, física y dibujo
Conviene dividir el programa en tres responsabilidades: los objetos almacenan el estado, las funciones físicas calculan derivadas y la interfaz transforma los resultados en píxeles.
Si la función gravitatoria no conoce Canvas ni botones, puede probarse con entradas pequeñas y reutilizarse en otros proyectos.
34.2 Estado mínimo de un cuerpo
Para una simulación plana necesitamos masa, posición y velocidad:
El nombre, color y radio de dibujo son metadatos útiles, pero no deben confundirse con las magnitudes que intervienen en la ecuación.
34.3 Elegir nombres y unidades explícitas
Propiedades como xKm o documentación que declare “todas las longitudes están en metros” reducen errores. La alternativa es encapsular las unidades en tipos, aunque JavaScript no lo hace de forma nativa.
Dentro del núcleo físico debe existir una única convención coherente para masa, longitud y tiempo.
34.4 Fábrica de cuerpos
Una función constructora centraliza valores predeterminados y validaciones:
Es preferible rechazar masas negativas, coordenadas no finitas o campos ausentes al crear el objeto, no muchos pasos después cuando aparece un NaN.
34.5 Vector de separación
Para calcular la aceleración de i causada por j:
Δy = yj − yi
r² = Δx² + Δy²
El orden j − i hace que el vector apunte desde el cuerpo acelerado hacia la fuente.
34.6 Evitar normalizaciones innecesarias
La forma μ/r² por el vector unitario r⃗/r puede combinarse:
Se calcula r² una vez, luego r = √r² y finalmente 1/r³. Así obtenemos las componentes sin construir un objeto vector unitario intermedio.
34.7 La masa del cuerpo acelerado se cancela
La fuerza contiene mimj, pero al dividir por mi queda Gmj. En ausencia de otras fuerzas, todos los cuerpos en el mismo punto reciben igual aceleración.
La masa de i sigue siendo necesaria porque determina su influencia sobre los demás cuerpos.
34.8 Acumular contribuciones
La aceleración total empieza en cero y suma una contribución por cada fuente distinta:
El acumulador debe reiniciarse en cada evaluación. Dejar la aceleración del paso anterior provoca un crecimiento artificial.
34.9 Instantánea consistente del sistema
Todas las aceleraciones de un instante deben calcularse con el mismo conjunto de posiciones. No se debe mover el primer cuerpo y usar esa nueva posición para calcular el segundo.
El ciclo correcto tiene dos fases: evaluar todas las aceleraciones y, después, actualizar todos los estados mediante el integrador.
34.10 Bucle doble directo
La implementación más clara recorre cada cuerpo i y todas las fuentes j, omitiendo i === j. Realiza N(N − 1) contribuciones y es adecuada para aprender o trabajar con pocos cuerpos.
Antes de optimizar conviene conservar esta versión como referencia para comparar resultados.
34.11 Recorrer pares una sola vez
Un recorrido con j > i evalúa N(N − 1)/2 separaciones. A partir del mismo factor aplica aceleraciones opuestas ponderadas por las masas:
a⃗j −= Gmir⃗ij/r³
Además de ahorrar operaciones, esta simetría favorece la conservación del momento lineal.
34.12 Distancia cero
Dos partículas puntuales en la misma posición producen una división por cero. Ignorar el par oculta el problema y cambia la física sin avisar.
Según el modelo, podemos detectar una colisión, combinar cuerpos, resolver contacto o introducir un suavizado documentado.
34.13 Suavizado de Plummer
Una variante habitual reemplaza r³ por (r² + ε²)3/2:
ε limita la aceleración cerca del origen. Es útil para distribuciones continuas o visualizaciones, pero no equivale a una colisión física entre esferas rígidas.
34.14 Radio físico y radio visual
El radio usado para colisiones pertenece al modelo y usa las mismas unidades que la posición. El radio visual se mide en píxeles y puede amplificarse para que un planeta sea visible.
Usar el tamaño dibujado como distancia de colisión produce resultados dependientes del zoom.
34.15 Partículas de prueba
Una partícula con masa gravitatoria cero recibe aceleración pero no modifica a las fuentes. Es útil para dibujar líneas de campo, explorar órbitas o aproximar el problema restringido.
En el código debemos decidir explícitamente si masa cero significa “partícula de prueba” o un dato inválido.
34.16 Crear cuerpos con JavaScript
function crearCuerpo(datos) {
const valores = [datos.masa, datos.x, datos.y, datos.vx, datos.vy];
if (!valores.every(Number.isFinite) || datos.masa < 0) {
throw new TypeError("El estado contiene valores inválidos");
}
return {
nombre: datos.nombre ?? "Cuerpo",
masa: datos.masa,
posicion: { x: datos.x, y: datos.y },
velocidad: { x: datos.vx, y: datos.vy },
radioFisico: datos.radioFisico ?? 0,
color: datos.color ?? "#ffffff"
};
}
const planeta = crearCuerpo({
nombre: "Planeta", masa: 5.972e24,
x: 0, y: 0, vx: 0, vy: 0, radioFisico: 6.371e6
});
console.log(planeta);
34.17 Aceleración de un cuerpo con JavaScript
function aceleracionSobre(indice, cuerpos, G = 6.67430e-11) {
const origen = cuerpos[indice];
let ax = 0, ay = 0;
cuerpos.forEach((fuente, j) => {
if (j === indice) return;
const dx = fuente.x - origen.x;
const dy = fuente.y - origen.y;
const r2 = dx * dx + dy * dy;
if (r2 === 0) throw new RangeError("Cuerpos superpuestos");
const factor = G * fuente.masa / (r2 * Math.sqrt(r2));
ax += factor * dx;
ay += factor * dy;
});
return { x: ax, y: ay };
}
const cuerpos = [
{ masa: 5.972e24, x: 0, y: 0 },
{ masa: 1000, x: 7e6, y: 0 }
];
console.log(aceleracionSobre(1, cuerpos));
34.18 Laboratorio: campo y aceleraciones
Arrastrá cualquier cuerpo para cambiar la geometría. El fondo muestra el campo debido a todas las masas y la flecha blanca representa la aceleración del cuerpo seleccionado. Las posiciones permanecen fijas para estudiar un solo instante.
Sonda seleccionada. Arrastrá un cuerpo o cambiá el suavizado para recalcular el campo.
34.19 Leer el laboratorio
- cerca de una masa, el campo cambia rápidamente y las flechas se curvan hacia ella;
- entre masas comparables puede existir un punto donde las contribuciones se cancelan;
- el cuerpo seleccionado no se atrae a sí mismo;
- aumentar ε suaviza las regiones próximas, pero también modifica el campo calculado;
- la escala visual de flechas no cambia los resultados numéricos.
34.20 Rendimiento y memoria
Crear miles de objetos temporales en cada cuadro aumenta el trabajo del recolector de basura. En simulaciones grandes se reutilizan arreglos de aceleración y se almacenan componentes en arreglos planos o tipados.
La claridad es prioritaria mientras N sea pequeño. La optimización debe medirse con un perfilador y comprobarse contra la versión sencilla.
34.21 Pruebas recomendadas
- una sola fuente sobre el eje x debe producir ay = 0;
- dos fuentes iguales y simétricas deben cancelarse en el centro;
- duplicar una masa debe duplicar su contribución;
- duplicar la distancia debe reducir la aceleración a un cuarto sin suavizado;
- trasladar o rotar todo el sistema debe trasladar o rotar el resultado;
- la suma de fuerzas internas debe ser aproximadamente cero.
34.22 Ejercicio propuesto
Con G = 1, una partícula de prueba está en (0, 0). Una masa 4 está en (3, 0) y una masa 2 está en (0, −2).
- Calculá la contribución de cada masa.
- Obtené las componentes de la aceleración total.
- Calculá su módulo y dirección.
Ver solución
La masa 4 produce (4/9, 0). La masa 2 produce (0, −2/2²) = (0, −1/2).
a⃗ = (0,4444; −0,5000), |a⃗| ≈ 0,66898 y el ángulo es aproximadamente −48,37° desde +x.
const ax = 4 * 3 / 3 ** 3;
const ay = 2 * (-2) / 2 ** 3;
const modulo = Math.hypot(ax, ay);
const angulo = Math.atan2(ay, ax) * 180 / Math.PI;
console.log("ax:", ax.toFixed(4));
console.log("ay:", ay.toFixed(4));
console.log("|a|:", modulo.toFixed(5));
console.log("ángulo:", angulo.toFixed(2), "grados");
34.23 Errores frecuentes
- usar i − j y hacer que la gravedad resulte repulsiva;
- dividir por r² sin multiplicar por un vector unitario;
- incluir el propio cuerpo en la suma;
- no reiniciar los acumuladores de aceleración;
- mezclar posiciones antiguas y actualizadas en una misma evaluación;
- confundir radio físico con radio de dibujo;
- permitir valores no finitos y buscar el error mucho más tarde.
34.24 Ideas para recordar
- El estado físico debe estar separado de la visualización.
- El vector de separación apunta desde el cuerpo acelerado hacia la fuente.
- Las contribuciones se suman por componentes.
- Todas las aceleraciones deben usar la misma instantánea de posiciones.
- El recorrido por pares aprovecha la simetría de las fuerzas internas.
- El suavizado es una decisión del modelo, no una reparación universal.
- Casos simétricos y leyes de escala ofrecen pruebas simples y potentes.
En el próximo tema utilizaremos estas aceleraciones para estudiar la integración numérica de órbitas y la elección del paso temporal.