Introducción al Desarrollo de Videojuegos con GameMaker · Módulo 9: Música, efectos sonoros y partículas.

Introducción al sistema de partículas

Clase 43 de 60 · 60 min

También disponible en: EN

¿Qué es un sistema de partículas y por qué usarlo?

En el desarrollo de videojuegos en dos dimensiones, la retroalimentación visual es indispensable para transmitir dinamismo y contundencia. Efectos como chispas al golpear una espada, columnas de humo emanando de una antorcha, polvo levantado tras un salto o estallidos al derrotar a un enemigo enriquecen enormemente la experiencia del jugador. En los módulos anteriores hemos creado objetos interactivos como el jugador (obj_player), enemigos patrulleros (obj_enemy) y monedas coleccionables (obj_coin). Una tentación común entre principiantes consiste en instanciar decenas de objetos convencionales con sprites animados cada vez que ocurre una explosión. Sin embargo, este enfoque resulta sumamente ineficiente.

Cada instancia de un objeto en GameMaker acarrea una sobrecarga técnica considerable: almacena docenas de variables internas predeterminadas (x, y, hspeed, vspeed, mask_index, depth, solid, etc.), evalúa sus propios eventos (Create, Step, Draw) y participa en el árbol de colisiones del motor. Si una explosión genera 150 esquirlas simultáneas y se producen varias explosiones consecutivas, la tasa de fotogramas por segundo (FPS) colapsará rápidamente. Para solucionar este problema existen las partículas: entidades gráficas ultraligeras, desprovistas de eventos individuales complejos y optimizadas matemáticamente a bajo nivel para dibujarse en masa mediante un único proceso unificado.

La arquitectura del sistema de partículas en GameMaker

El subsistema de partículas de GameMaker opera bajo un modelo jerárquico compuesto por tres elementos esenciales: el Sistema de Partículas (Particle System), el Tipo de Partícula (Particle Type) y el Emisor de Partículas (Particle Emitter). Comprender la relación entre estas tres piezas es indispensable para estructurar código modular, limpio y libre de errores de rendimiento.

Diagrama esquemático que ilustra la arquitectura de partículas en GameMaker: el Sistema como contenedor general, el Tipo como molde de propiedades y el Emisor generando partículas en un área.
Figura 1: Relación modular entre el sistema contenedor, la definición de tipo y los métodos de emisión. · Imagen generada con IA

El Sistema de Partículas (Particle System) es el gestor global o lienzo contenedor. Determina en qué capa (layer) o profundidad visual se representarán las partículas, actualiza la posición de todas las partículas activas en cada ciclo de juego y administra la memoria interna dedicada a ellas. El Tipo de Partícula (Particle Type) actúa como una plantilla o molde que define cómo se ve y cómo se comporta una partícula individual: su forma geométrica o sprite, su tamaño inicial y final, sus transiciones de color, su velocidad, su dirección de movimiento, su aceleración y su tiempo de vida en fotogramas. Finalmente, el Emisor (Particle Emitter) es una herramienta opcional que permite delimitar una región geográfica dentro del escenario (un rectángulo, elipse, diamante o línea) para expulsar partículas de forma continua o mediante ráfagas periódicas.

Ciclo de vida y gestión de memoria dinámica

A diferencia de las variables numéricas estándar o los sprites gestionados automáticamente por el recolector de basura de GameMaker, los sistemas, tipos y emisores de partículas residen en memoria dinámica del sistema (punteros o índices de estructuras de datos). Si creas un sistema de partículas dentro del evento Create de un objeto y la sala (room) se reinicia sin liberar esos recursos, la memoria utilizada quedará ocupada permanentemente en la memoria RAM. Este fallo crítico se conoce como fuga de memoria (memory leak) y terminará provocando cierres inesperados del juego. Por tanto, cada recurso de partículas creado debe destruirse formalmente cuando el objeto gestor termine su ciclo de vida.

Función GMLPropósitoMomento de uso recomendado
part_system_create()Inicializa un nuevo gestor de partículas en memoria.Evento Create de un objeto controlador.
part_system_create_layer()Crea el sistema anclado directamente a una capa del Room.Evento Create cuando se requiere orden de dibujo estricto.
part_type_create()Reserva memoria para definir un nuevo molde gráfico de partícula.Evento Create, tras inicializar el sistema.
part_particles_create()Genera partículas de un tipo específico en una coordenada X/Y puntual.Eventos Step o eventos de colisión para impactos inmediatos.
part_type_destroy(tipo)Libera de la memoria RAM la definición del tipo de partícula.Evento Clean Up del objeto controlador.
part_system_destroy(sistema)Elimina el sistema contenedor y destruye todas sus partículas activas.Evento Clean Up del objeto controlador.

Paso a paso: Creación de un efecto de chispas por impacto

Para nuestro proyecto de plataformas 2D retro, construiremos un objeto controlador centralizado de efectos visuales llamado obj_fx_manager. Este objeto será el encargado de inicializar los sistemas y tipos de partículas que utilizarán tanto el jugador al recolectar monedas o impactar contra paredes, como los enemigos al ser golpeados. Comenzaremos implementando un efecto clásico de chispas luminosas que se dispersan en forma radial y se desvanecen gradualmente.

Abre tu proyecto, crea un nuevo objeto en el Asset Browser con el nombre obj_fx_manager y añade el evento Create. En este evento escribiremos la definición completa del sistema y las propiedades del tipo de chispa:

// --- OBJ_FX_MANAGER: EVENTO CREATE ---
// 1. Crear el sistema de partículas global
sys_efectos = part_system_create();

// Asignar una profundidad visual para que aparezca por delante de los tiles y personajes
part_system_depth(sys_efectos, -100);

// 2. Crear y definir el tipo de partícula para chispas
part_chispa = part_type_create();

// Forma predeterminada del motor (usamos pt_shape_spark para aspecto retro luminoso)
part_type_shape(part_chispa, pt_shape_spark);

// Tamaño: escala inicial entre 0.1 y 0.2, reduciéndose -0.005 en cada fotograma
part_type_size(part_chispa, 0.1, 0.2, -0.005, 0);

// Color: transición desde amarillo brillante hasta rojo anaranjado
part_type_color2(part_chispa, c_yellow, c_red);

// Transparencia (Alfa): nace completamente opaco (1.0) y desaparece a transparente (0.0)
part_type_alpha2(part_chispa, 1.0, 0.0);

// Velocidad: entre 2 y 5 píxeles por fotograma, con leve desaceleración (-0.1)
part_type_speed(part_chispa, 2.0, 5.0, -0.1, 0);

// Dirección: expulsión omnidireccional en 360 grados sin rotación forzada
part_type_direction(part_chispa, 0, 360, 0, 0);

// Gravedad sutil: 0.15 píxeles por fotograma apuntando hacia abajo (270 grados)
part_type_gravity(part_chispa, 0.15, 270);

// Vida útil: la partícula existirá entre 15 y 30 fotogramas
part_type_life(part_chispa, 15, 30);

// Mezcla aditiva para simular brillo incandescente
part_type_blend(part_chispa, true);

💡 GameMaker incluye múltiples formas predefinidas listas para usar mediante constantes: pt_shape_pixel, pt_shape_disk, pt_shape_square, pt_shape_line, pt_shape_star, pt_shape_circle, pt_shape_ring, pt_shape_sphere, pt_shape_flare, pt_shape_spark, pt_shape_explosion, pt_shape_cloud, pt_shape_smoke y pt_shape_snow. Estas formas permiten diseñar prototipos rápidos sin necesidad de importar sprites personalizados.

Ahora que el tipo de partícula está configurado, necesitamos un método para dispararlo en el momento y lugar exactos en los que ocurra una acción en el juego. Para efectos instantáneos, no es necesario crear un emisor; la función part_particles_create() permite generar una cantidad fija de partículas en una posición precisa (x, y) de forma inmediata.

Por ejemplo, dentro del evento de colisión de obj_player con obj_coin, o en el evento Destroy de obj_coin cuando el jugador la recoge, podemos invocar el sistema del gestor para detonar una explosión de chispas doradas:

// --- OBJ_COIN: EVENTO DESTROY (o evento de colisión con obj_player) ---
// Verificar que el gestor de partículas exista antes de emitir
if (instance_exists(obj_fx_manager)) {
    // Genera 12 chispas centradas exactamente en la moneda recolectada
    part_particles_create(obj_fx_manager.sys_efectos, x, y, obj_fx_manager.part_chispa, 12);
}

Para evitar fugas de memoria, es obligatorio programar el evento Clean Up en obj_fx_manager. A diferencia del evento Destroy (que solo se ejecuta si la instancia es destruida explícitamente mediante instance_destroy()), el evento Clean Up se ejecuta siempre: al salir de la sala, al cambiar de nivel, al reiniciar la partida o al cerrar la ventana del juego.

// --- OBJ_FX_MANAGER: EVENTO CLEAN UP ---
// Destruir primero los tipos de partícula asociados
if (part_type_exists(part_chispa)) {
    part_type_destroy(part_chispa);
}

// Destruir el sistema general al final
if (part_system_exists(sys_efectos)) {
    part_system_destroy(sys_efectos);
}

Emisores de partículas: Flujos continuos y áreas ambientales

Mientras que part_particles_create() es ideal para eventos discretos (impactos, pasos, monedas recogidas), los emisores de partículas (part_emitter) están pensados para definir una zona en el espacio geométrico y verter partículas de manera constante a lo largo del tiempo o disparar ráfagas en áreas extensas. Esto resulta perfecto para crear lluvia, nieve, polvo ambiental flotante en una cueva o chorros de vapor y lava.

// --- OBJ_FX_MANAGER: EXTENSIÓN DEL EVENTO CREATE ---
// 1. Tipo de partícula para ceniza
part_ceniza = part_type_create();
part_type_shape(part_ceniza, pt_shape_pixel);
part_type_size(part_ceniza, 0.5, 1.2, 0, 0);
part_type_color3(part_ceniza, c_orange, c_red, c_dkgray);
part_type_alpha3(part_ceniza, 0.0, 0.8, 0.0); // Aparece suave, brilla y se apaga
part_type_speed(part_ceniza, 0.3, 1.0, 0, 0);
part_type_direction(part_ceniza, 80, 100, 0, 2); // Movimiento ascendente ondulante
part_type_life(part_ceniza, 120, 240); // Larga duración (2 a 4 segundos a 60 FPS)

// 2. Creación del emisor ambiental
emisor_ambiente = part_emitter_create(sys_efectos);

// Delimitar la región: cubre todo el ancho del nivel desde el fondo inferior
// Parámetros: emisor, xmin, xmax, ymin, ymax, forma de región, distribución
part_emitter_region(
    sys_efectos,
    emisor_ambiente,
    0,
    room_width,
    room_height - 32,
    room_height,
    ps_shape_rectangle,
    ps_distr_linear
);

// 3. Iniciar flujo continuo: emite 2 partículas por cada fotograma
part_emitter_stream(sys_efectos, emisor_ambiente, part_ceniza, 2);

Cuando se emplean emisores, es fundamental recordar que también ocupan memoria propia dentro del sistema. Si bien la función part_system_destroy() destruye automáticamente todos los emisores asociados al sistema, es una buena práctica de ingeniería liberar los emisores con part_emitter_destroy() si se van a recrear o reconfigurar dinámicamente en tiempo de ejecución.

Comparativa técnica: Creación puntual frente a Emisores continuos

Criteriopart_particles_create()part_emitter_stream() / burst()
Consumo de recursosMínimo (no requiere entidad emisora intermedia).Ligeramente superior (almacena coordenadas de región y tasa).
Caso de uso idealEfectos puntuales (chispazos, pisadas, golpes, recolección).Efectos climáticos continuos o áreas volumétricas (lluvia, humo continuo).
Control espacialPreciso en coordenadas (x, y) de un objeto o contacto.Delimitado a una región geométrica (rectángulo, elipse, diamante).
Gestión de cicloSe ejecuta una sola vez por llamada de código.Emite automáticamente en cada fotograma hasta que se detenga.

Equivalencia en GML Visual

Para aquellos estudiantes que exploren GameMaker mediante bloques de GML Visual, la lógica subyacente es exactamente idéntica. En la sección de acciones de partículas existen bloques como 'Create Particle System', 'Create Particle Type', 'Set Particle Shape', 'Set Particle Size' y 'Emit Particles'. Cada uno de estos bloques ejecuta internamente las funciones GML descritas con anterioridad. Sin embargo, en proyectos comerciales o de mediana envergadura, escribir la configuración en GML Code dentro del evento Create resulta infinitamente más rápido de ajustar, versionar y mantener legible.

Ejercicios prácticos

Resumen

  • Las partículas son entidades gráficas de alto rendimiento gestionadas a nivel interno por el motor, diseñadas para evitar la sobrecarga computacional de las instancias tradicionales.
  • Un sistema completo se compone de: Sistema (gestor global de ciclo y capa), Tipo (molde de aspecto, movimiento y vida) y opcionalmente Emisor (generador por zonas y flujos continuos).
  • Los tipos y sistemas de partículas se alojan en memoria dinámica: es imperativo destruirlos en el evento Clean Up mediante part_type_destroy() y part_system_destroy() para evitar fugas de memoria críticas.
  • Para impactos y eventos puntuales (monedas, chispas, disparos) se recomienda part_particles_create(); para fenómenos meteorológicos o ambientales continuos se utiliza part_emitter_stream().

Practica lo aprendido

Ejercicio 1 · 1 punto

Relaciona cada componente de la arquitectura del subsistema de partículas de GameMaker con la función técnica que desempeña:

  • Sistema de Partículas (Particle System)
  • Tipo de Partícula (Particle Type)
  • Emisor de Partículas (Particle Emitter)
Practicas sin cuenta: no se guarda nada. Regístrate para guardar tu progreso.

Ejercicio 2 · 1 punto

¿Por qué es fundamental liberar los sistemas y tipos de partículas en el evento Clean Up en lugar del evento Destroy dentro de GameMaker?

Practicas sin cuenta: no se guarda nada. Regístrate para guardar tu progreso.

Ejercicio 3 · 2 puntos

Dentro del evento Clean Up de obj_fx_manager, completa la liberación de memoria dinámica destruyendo primero el tipo de partícula 'part_chispa' y luego el sistema general 'sys_efectos'.

Tu código no se ejecuta: se comprueban requisitos concretos sobre el texto.

Practicas sin cuenta: no se guarda nada. Regístrate para guardar tu progreso.

Ingresa para guardar tu progreso — Ingresar