CodeForge

Maquetación Web Dinámica / Canvas y videojuegos 2D

Sistema de partículas: confeti, chispas y humo

Teoría22 min20 XP

El confeti que estalla al ganar, las chispas de una explosión, la nieve que cae, el humo de un cohete: todos son lo mismo — cientos de partículas diminutas, cada una con su propia física, que nacen, viven y mueren. Un sistema de partículas suena avanzado, pero es tu game loop y tu física de siempre, aplicados a un ARRAY de objetos. Y es el efecto que hace que un juego se sienta vivo y jugoso.

Un enjambre de bolitas tontas

La partícula y su ciclo de vida

Cada partícula es un objeto; el sistema es un array de ellos:

particula.js
function crearParticula(x, y) {
const angulo = Math.random() * Math.PI * 2;   // dirección al azar (360°)
const rapidez = Math.random() * 3 + 1;
return {
  x, y,
  vx: Math.cos(angulo) * rapidez,   // velocidad descompuesta en X e Y
  vy: Math.sin(angulo) * rapidez,
  vida: 1,                          // 1 = recién nacida, 0 = muerta
  color: `hsl(${Math.random() * 60 + 260}, 80%, 60%)`,  // violetas variados
  tam: Math.random() * 3 + 2,
};
}

const particulas = [];
// emitir un puñado desde un punto:
for (let i = 0; i < 30; i++) particulas.push(crearParticula(cx, cy));

Math.cos(angulo) y Math.sin(angulo) convierten "una dirección" en vx/vy — reparten la rapidez entre los dos ejes según el ángulo (la trigonometría justa, sin dramatismo: coseno para X, seno para Y). El azar en ángulo, rapidez, color y tamaño es lo que hace que 30 partículas se vean como una explosión y no como una formación militar.

El loop del sistema: actualizar y PODAR

sistema.js
function actualizarParticulas() {
for (const p of particulas) {
  p.vy += 0.08;          // gravedad
  p.x += p.vx; p.y += p.vy;
  p.vida -= 0.012;       // envejece: se acerca a la muerte
}
// PODAR las muertas: sin esto, el array crece infinito y el juego se traba
for (let i = particulas.length - 1; i >= 0; i--) {
  if (particulas[i].vida <= 0) particulas.splice(i, 1);
}
}
function dibujarParticulas() {
for (const p of particulas) {
  ctx.globalAlpha = p.vida;          // se desvanece al envejecer
  ctx.fillStyle = p.color;
  ctx.beginPath(); ctx.arc(p.x, p.y, p.tam, 0, Math.PI * 2); ctx.fill();
}
ctx.globalAlpha = 1;                 // restaurar, o TODO lo demás sale translúcido
}

Dos detalles que separan un sistema sano de uno que revienta: podar las partículas muertas (recorrer el array AL REVÉS para poder splice sin saltarte elementos) evita que el array crezca sin fin y congele el juego; y restaurar globalAlpha = 1 tras dibujar, porque globalAlpha es estado global — si lo dejas en 0.3, todo lo que pintes después (el puntaje, el personaje) saldrá translúcido.

Una fuente de partículas

Cambiando cuatro números tienes efectos distintos: apunta el ángulo hacia arriba con poca dispersión y es una fuente; 360° de dispersión desde un punto y es una explosión; emite desde arriba con vy positivo y poca vx, sin gravedad fuerte, y es nieve cayendo. Mismo sistema, otra física inicial. (Este patrón es, de hecho, el mismo que mueve el confeti que viste al completar una lección en esta plataforma.)

Tu efecto de confeti se ve genial 10 segundos y luego el juego entero empieza a ir a tirones cada vez peor. ¿La causa casi segura?

Mini-reto

Conecta las partículas a una acción: emite una ráfaga de 40 partículas en la posición donde el jugador RECOGE una moneda (reutiliza la colisión de la lección 7). Ese "feedback de partículas" al recoger, golpear o saltar es lo que los diseñadores llaman "juice" — y es la diferencia entre un juego que funciona y uno que se siente delicioso de jugar.

Qué sigue

Ya construyes efectos dignos de mostrar. La próxima lección, corta y práctica, resuelve una pregunta muy concreta: "¿cómo convierto mi animación de canvas en un GIF o un video para compartirla?". Las técnicas y las librerías para exportar, antes de lanzarnos a los dos proyectos grandes del módulo.