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

Importación y reproducción de efectos de sonido

Clase 41 de 60 · 45 min

También disponible en: EN

Introducción al diseño sonoro en videojuegos 2D

El sonido es responsable de más de la mitad del impacto perceptivo de un videojuego. Una animación de salto o un golpe contra un enemigo pueden estar perfectamente dibujados en píxeles, pero sin una respuesta auditiva sincronizada, la acción se siente desconectada y carente de peso. En el desarrollo de videojuegos nos referimos a esta respuesta física y sensorial como feedback o 'juice'. Los efectos de sonido (abreviados comúnmente como SFX, por Sound Effects) confirman al jugador que sus órdenes han sido recibidas y procesadas por el sistema.

Hasta el módulo anterior, nuestro proyecto de plataformas retro ya cuenta con mecánicas de movimiento, colisiones, enemigos básicos, recolección de monedas y una interfaz gráfica completa. Sin embargo, todas estas acciones ocurren en absoluto silencio. En esta lección comenzaremos a construir la capa sonora del juego, aprendiendo a importar archivos de audio, entender cómo GameMaker gestiona los recursos de sonido en memoria y utilizar la función nativa audio_play_sound para dar vida a los saltos, los impactos y la recolección de objetos.

Formatos de audio y el recurso Sound en GameMaker

En GameMaker, cualquier archivo sonoro que utilicemos se gestiona dentro del Asset Browser mediante el tipo de recurso Sound. Antes de importar sonidos, es fundamental comprender qué tipos de archivos son los más convenientes para los efectos sonoros rápidos frente a las pistas musicales de fondo.

Los dos formatos de audio más extendidos en el desarrollo con GameMaker son WAV (.wav) y OGG Vorbis (.ogg). Los archivos WAV contienen audio sin compresión o con compresión mínima, lo que preserva una fidelidad perfecta y no requiere tiempo de procesamiento por parte del procesador para descomprimirse. Esto los hace ideales para efectos de sonido breves e inmediatos (de menos de 1 a 2 segundos), como el chasquido de una moneda, el rebote de un salto o una explosión rápida. Por el contrario, los archivos OGG utilizan compresión con pérdida eficiente, ocupando mucho menos espacio en disco, lo que resulta óptimo para pistas de música largas o sonidos ambientales continuos.

Diagrama esquemático que compara la carga en memoria de un archivo WAV para efectos cortos frente al streaming de un archivo OGG para pistas continuas.
Figura 1: Gestión de memoria en GameMaker según el tipo de archivo y configuración del recurso Sound. · Imagen generada con IA

Al crear un nuevo recurso Sound en el Asset Browser (haciendo clic derecho sobre una carpeta y seleccionando Create -> Sound), se abre el Sound Editor. En este editor podemos nombrar el recurso siguiendo una convención clara (por ejemplo, el prefijo snd_), importar el archivo desde nuestro disco duro y configurar sus parámetros de compresión y atributos.

Opción en Sound EditorValores comunesRecomendación para SFX
Attributes (Atributos)Uncompress on load, Compressed - Streamed, CompressedUncompress on load para efectos inmediatos de corta duración.
Target Bitrate (Tasa de bits)64 kbps hasta 320 kbpsPara efectos de 8-bit / retro, 96 o 128 kbps es más que suficiente.
Channels (Canales)Mono, StereoMono para efectos de un solo canal (ahorra 50% de memoria); Stereo para efectos ambientales enriquecidos.
Volume (Volumen base)Control deslizante 0 a 1Mantener en 1.0 y calibrar los volúmenes individuales por código o grupos.

💡 Nota sobre memoria: Seleccionar 'Uncompress on load' descomprime el archivo completo directamente en la memoria RAM cuando se carga la room. Para efectos de sonido cortos (como saltos o disparos) esto garantiza una latencia cero al reproducir, evitando tirones en el rendimiento.

La función fundamental: audio_play_sound

En versiones modernas de GameMaker, la función estándar por excelencia para emitir sonidos en el espacio de juego es audio_play_sound. Su sintaxis básica recibe varios argumentos que determinan el recurso a reproducir, su prioridad y si debe ejecutarse en bucle o una sola vez:

// Firma clásica de la función:
audio_play_sound(soundid, priority, loop);

Analicemos cada uno de los parámetros de esta llamada:

1. soundid: El identificador del recurso Sound tal como lo definimos en el Asset Browser, por ejemplo, snd_salto o snd_moneda. 2. priority: Un valor numérico entero o decimal (habitualmente de 0 a 100) que indica la importancia relativa de este sonido frente a otros. Los sistemas operativos y los motores de audio poseen un límite físico de canales simultáneos (voces de hardware). Si el juego intenta reproducir más sonidos de los que el canal del sistema permite, GameMaker detendrá los sonidos con menor prioridad para favorecer a los de mayor prioridad. Un sonido de interfaz o de daño del jugador debe tener mayor prioridad (ej. 10) que un sonido ambiental secundario (ej. 1). 3. loop: Un valor booleano (true o false). Si pasamos true, el sonido continuará reproduciéndose indefinidamente hasta que sea detenido explícitamente mediante código. Para efectos breves (one-shot SFX) como saltos o golpes, este parámetro siempre debe ser false.

En versiones actualizadas de GameMaker, audio_play_sound admite parámetros opcionales adicionales, como ganancia (volumen), desfase de tiempo (offset) y modulación de tono (pitch):

// Firma extendida disponible en GameMaker moderno:
audio_play_sound(index, priority, loop, [gain], [offset], [pitch], [listener_mask]);

Esta sobrecarga nos permite ajustar el volumen relativo y la velocidad/tono de un sonido directamente en la misma línea de código, una técnica muy valiosa para evitar que los efectos repetitivos cansen el oído del jugador.

Implementación práctica 1: Efecto de salto en obj_jugador

En el Módulo 4 y Módulo 5 establecimos la lógica de movimiento vertical del jugador, gobernada por las variables vspd (velocidad vertical), grav (gravedad) y jump_spd (impulso de salto). Vamos a integrar el recurso de sonido snd_salto para que se reproduzca en el instante exacto en que el jugador se impulsa desde el suelo.

A continuación, abrimos el objeto obj_jugador y localizamos su evento Step, en la sección donde se evalúa si el jugador presiona la tecla de salto mientras está en contacto con el suelo (grounded):

// Objeto: obj_jugador
// Evento: Step

// Lectura de teclas (definidas en módulos previos)
var _key_jump = keyboard_check_pressed(vk_space) || keyboard_check_pressed(ord("W"));

// Lógica de salto cuando está sobre el suelo
if (en_suelo && _key_jump)
{
    vspd = -jump_spd;
    en_suelo = false;
    
    // Reproducción del efecto de sonido de salto
    // Prioridad 8 (alta importancia táctil), sin bucle (false)
    audio_play_sound(snd_salto, 8, false);
}

Observa que audio_play_sound se coloca dentro de la condición keyboard_check_pressed. Si hubiésemos usado keyboard_check (continuo), el sonido intentaría reiniciarse en cada fotograma sucesivo mientras la tecla estuviera presionada, provocando un fallo acústico conocido como ametrallamiento de audio.

Implementación práctica 2: Recolección de monedas e ítems

En el Módulo 7 implementamos el objeto obj_moneda como un coleccionable que incrementaba la variable global.monedas al colisionar con obj_jugador. La retroalimentación auditiva es crucial aquí para que el jugador sepa de inmediato que el ítem fue registrado con éxito.

Vamos a crear el recurso snd_moneda con un tono brillante tipo campana o arpegio agudo. Existen dos formas canónicas de programar esta colisión: en el evento de colisión de obj_jugador con obj_moneda, o en el evento de colisión de obj_moneda con obj_jugador. Lo más limpio para la modularidad de los ítems es que el propio objeto coleccionable gestione su destrucción y su sonido:

// Objeto: obj_moneda
// Evento: Collision con obj_jugador

// Aumentar la puntuación o contador global
global.monedas += 1;
global.puntos += 100;

// Reproducir sonido de recolección
// Prioridad 6, sin bucle
audio_play_sound(snd_moneda, 6, false);

// Destruir la instancia de la moneda en la sala actual
instance_destroy();

¿Por qué el sonido continúa sonando si destruimos la instancia en la siguiente línea? Esta es una duda habitual entre principiantes. En GameMaker, audio_play_sound envía la orden de reproducción al subsistema global de audio del motor. Una vez emitida la orden, el sonido no pertenece a la instancia que lo llamó; sigue existiendo en el mezclador del motor hasta terminar su duración natural, independientemente de que la instancia emisora se destruya de inmediato.

Implementación práctica 3: Daño del jugador y retroceso (Knockback)

El tercer efecto crítico de esta lección es el sonido de golpe o daño. En el Módulo 7 programamos la interacción entre obj_jugador y obj_enemigo_patrulla, restando una vida y activando un periodo de invulnerabilidad temporal para evitar daño continuo inmediato.

Crearemos el recurso snd_golpe, correspondiente a un sonido sordo, pesado o distorsionado. En el evento Collision de obj_jugador con obj_enemigo_patrulla, integramos la llamada condicional:

// Objeto: obj_jugador
// Evento: Collision con obj_enemigo_patrulla

// Solo procesar si el jugador no está en periodo de inmunidad
if (!es_invulnerable)
{
    global.vidas -= 1;
    es_invulnerable = true;
    tiempo_invulnerable = 60; // 60 pasos (aprox. 1 segundo a 60 FPS)
    
    // Aplicar retroceso vertical y horizontal
    vspd = -4;
    hspd = (x < other.x) ? -5 : 5;
    
    // Reproducir el sonido de impacto con máxima prioridad
    // Prioridad 10 (máxima prioridad táctica para el jugador)
    audio_play_sound(snd_golpe, 10, false);
    
    // Comprobar derrota si se agotaron las vidas
    if (global.vidas <= 0)
    {
        // Lógica de Game Over tratada en el Módulo 8
        room_goto(rm_gameover);
    }
}

Asignar una prioridad alta (10) a snd_golpe garantiza que, incluso si en ese mismo instante coinciden sonidos de explosiones, monedas o disparos en pantalla, el golpe al jugador jamás será silenciado por el hardware.

Técnica profesional: Variación de tono (Pitch Shifting)

Un problema recurrente en los videojuegos clásicos es la fatiga auditiva: cuando un sonido idéntico se reproduce docenas de veces por minuto (por ejemplo, al recolectar un grupo de cinco monedas seguidas o dar saltos continuos), el oído humano lo percibe monótono y artificial.

Podemos solucionar esto fácilmente usando modulación de tono aleatoria (pitch shifting). En GameMaker, el tono base de un sonido es 1.0. Un valor de 1.1 lo hace ligeramente más agudo y rápido, mientras que 0.9 lo hace más grave y lento. Modificar sutilmente este parámetro en cada ejecución produce una sensación orgánica con un único archivo de audio.

// Variante dinámica para la recolección de monedas
// Objeto: obj_moneda (Evento Collision con obj_jugador)

global.monedas += 1;

// Generar una variación sutil de tono entre 0.95 y 1.05
var _tono_aleatorio = random_range(0.95, 1.05);

// Uso de audio_play_sound con argumentos extendidos:
// soundid, priority, loop, gain, offset, pitch
audio_play_sound(snd_moneda, 6, false, 1.0, 0, _tono_aleatorio);

instance_destroy();

Con solo dos líneas adicionales, cada moneda recolectada emitirá una nota sutilmente distinta, enriqueciendo la experiencia de juego de manera sustancial sin añadir peso en megabytes al proyecto.

Actividades prácticas guiadas

Para afianzar el dominio de la importación y reproducción de efectos sonoros, realiza los siguientes tres ejercicios prácticos en tu proyecto.

Resumen

  • Los efectos de sonido (SFX) proporcionan confirmación táctil y enriquecen la inmersión del jugador en el entorno interactivo.
  • El formato WAV con el atributo 'Uncompress on load' es el estándar recomendado en GameMaker para efectos de sonido breves y de respuesta inmediata.
  • La función audio_play_sound(soundid, priority, loop) es la herramienta nuclear para disparar efectos sonoros puntuales.
  • El parámetro de prioridad (priority) previene que sonidos cruciales de jugabilidad (como recibir daño) sean cancelados por efectos secundarios.
  • Los sonidos emitidos no se destruyen al eliminar la instancia que los invocó, ya que su ciclo de vida es administrado de manera independiente por el motor de audio.
  • La modulación dinámica del tono (pitch) con random_range previene eficazmente la monotonía auditiva sin requerir múltiples archivos de audio.

Practica lo aprendido

Ejercicio 1 · 1 punto

Empareja cada parámetro o ajuste relacionado con el audio en GameMaker con su descripción técnica correspondiente:

  • soundid
  • priority
  • loop
  • Uncompress on load
Practicas sin cuenta: no se guarda nada. Regístrate para guardar tu progreso.

Ejercicio 2 · 2 puntos

Escribe la llamada a la función para reproducir el efecto de salto usando el recurso `snd_salto`, con una prioridad de `8` y configurado para que no se reproduzca en bucle.

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.

Ejercicio 3 · 1 punto

Al colisionar con una moneda se ejecuta la instrucción audio_play_sound(snd_moneda, 6, false); e inmediatamente después instance_destroy();. ¿Qué sucede con el sonido?

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

Ingresa para guardar tu progreso — Ingresar