Parte: 1 — Motores 2D y tu primer juego jugable · Fuente: Documentación de Godot 4 (Audio) ⏱️ Duración estimada: 90 min · Nivel: Intermedio
Darle voz a tu plataformas. Hasta ahora el juego se mueve pero es mudo; en esta clase incorporarás efectos de sonido (SFX) y música de fondo usando el sistema de audio de Godot 4. Aprenderás la diferencia entre reproducir un sonido "global" y uno "posicional" que se atenúa con la distancia, cómo organizar el volumen mediante buses de audio (Master, Music, SFX) y cómo mantener la música sonando de forma continua aunque cambies de escena.
Al terminar tendrás un Autoload de música que no se corta entre pantallas y efectos de sonido disparados por señales en los eventos clave: saltar, recoger una moneda y recibir daño. Es la capa que hace que el juego "se sienta" vivo, y la base sobre la que en la próxima clase añadiremos partículas y feedback visual.
Al finalizar, el alumno podrá:
AudioServer.| # | Tema | Por qué importa |
|---|---|---|
| 1 | Formatos de audio (WAV vs OGG) | Cada uno sirve a un propósito: SFX cortos vs música larga. |
| 2 | AudioStreamPlayer global | Reproduce sonidos que se oyen igual en toda la pantalla. |
| 3 | AudioStreamPlayer2D posicional | Aporta sensación de espacio: el sonido depende de la posición. |
| 4 | Buses de audio | Permiten controlar volúmenes por categoría (música/efectos). |
| 5 | Loop de música en OGG | La música debe repetirse sin cortes ni silencios. |
| 6 | SFX por señales | Desacopla el sonido de la lógica: se dispara ante eventos. |
| 7 | Autoload de música | Mantiene la banda sonora entre escenas sin reiniciarla. |
| 8 | Control de volumen en runtime | Base de un futuro menú de ajustes de sonido. |
0 es el nivel nominal y valores negativos lo bajan. Clave: -80 equivale a silencio.set_bus_volume_db, índices de bus). Clave: base de los ajustes de volumen.Necesitas tu proyecto PlataformasCurso de las clases anteriores y Godot 4.x. Consigue algunos efectos cortos en formato WAV (salto, moneda, daño) y una pista de música en OGG; puedes generar SFX libres de derechos con herramientas como jsfxr (https://sfxr.me) y encontrar música con licencia libre. Coloca los archivos en una carpeta res://audio/. Ten a mano la documentación oficial de audio: https://docs.godotengine.org/en/stable/tutorials/audio/audio_streams.html y la de buses: https://docs.godotengine.org/en/stable/tutorials/audio/audio_buses.html.
Configuraremos los buses, un Autoload de música persistente y SFX disparados por señales.
Importar la música con loop. Copia tu pista OGG a res://audio/musica_nivel.ogg. Selecciónala en el panel FileSystem, ve a la pestaña Import (arriba a la derecha), activa Loop y pulsa Reimport. Repite para los WAV de SFX, pero deja Loop desactivado en ellos.
Crear los buses de audio. Abre el panel Audio (barra inferior del editor). Pulsa Add Bus dos veces y renómbralos Music y SFX. Ambos deben enviar su salida a Master (columna "Send"). Así podrás bajar la música sin tocar los efectos.
Crear el Autoload de música. Crea un script res://audio/musica.gd:
extends Node
# Reproductor de música persistente. Vive sobre todas las escenas.
@onready var reproductor: AudioStreamPlayer = $Reproductor
func _ready() -> void:
# Al arrancar el juego, iniciamos la banda sonora una sola vez.
reproducir(preload("res://audio/musica_nivel.ogg"))
func reproducir(pista: AudioStream) -> void:
# Evita reiniciar si ya suena la misma pista.
if reproductor.stream == pista and reproductor.playing:
return
reproductor.stream = pista
reproductor.play()
func detener() -> void:
reproductor.stop()
Montar la escena del Autoload. Crea una escena nueva con raíz Node llamada Musica, añádele un hijo AudioStreamPlayer renombrado Reproductor y asígnale en el Inspector el Bus Music. Adjunta el script musica.gd a la raíz y guarda como res://audio/musica.tscn.
Registrar el Autoload. Ve a Project → Project Settings → Globals → Autoload, selecciona res://audio/musica.tscn, nómbralo Musica y pulsa Add. Ahora es un singleton global. Ejecuta con F5: la música suena. Cambia de escena y comprobarás que no se reinicia.
Crear un gestor de SFX. Muchos efectos son globales (moneda, daño). Crea un Autoload similar res://audio/sfx.gd:
extends Node
# Precargamos los efectos una vez para no leer disco en cada disparo.
var sonidos := {
"salto": preload("res://audio/salto.wav"),
"moneda": preload("res://audio/moneda.wav"),
"dano": preload("res://audio/dano.wav"),
}
@onready var reproductor: AudioStreamPlayer = $Reproductor
func reproducir(nombre: String) -> void:
if not sonidos.has(nombre):
push_warning("SFX inexistente: " + nombre)
return
reproductor.stream = sonidos[nombre]
reproductor.play()
Móntalo igual que el de música (raíz Node, hijo AudioStreamPlayer en el bus SFX) y regístralo como Autoload Sfx.
func _physics_process(delta: float) -> void:
# ... lógica de movimiento previa ...
if Input.is_action_just_pressed("saltar") and is_on_floor():
velocity.y = FUERZA_SALTO
Sfx.reproducir("salto") # SFX global al saltar
move_and_slide()
func recibir_dano(cantidad: int) -> void:
vida -= cantidad
Sfx.reproducir("dano")
extends Area2D
@onready var sonido: AudioStreamPlayer2D = $SonidoMoneda
func _on_body_entered(cuerpo: Node2D) -> void:
if cuerpo.is_in_group("jugador"):
sonido.play() # suena desde la posición de la moneda
$Sprite2D.visible = false
set_deferred("monitoring", false)
# Esperamos a que termine el sonido antes de liberar el nodo.
await sonido.finished
queue_free()
Asigna el AudioStreamPlayer2D al bus SFX en su Inspector. Ejecuta con F5 y prueba: saltar, recoger monedas y recibir daño deben sonar, con la música de fondo continua.
-10 dB desde el Inspector del Reproductor y compáralo con los SFX.is_on_floor().Sfx.silenciar(mute: bool) que active/desactive el mute del bus SFX con AudioServer.set_bus_mute.Musica.reproducir(...) con otra pista OGG.AudioStreamPlayer2D de la moneda y describe cómo cambia la atenuación.pitch_scale) al SFX de moneda para que no suene idéntico cada vez.Implementa un control de volumen por bus. Crea en el Autoload Sfx (o uno nuevo AudioConfig) dos funciones: set_volumen_musica(porcentaje: float) y set_volumen_sfx(porcentaje: float), que reciban un valor de 0.0 a 1.0 y lo apliquen al bus correcto usando AudioServer.get_bus_index("Music") y AudioServer.set_bus_volume_db(idx, linear_to_db(porcentaje)).
Criterio de aceptación: al llamar set_volumen_musica(0.5) la música baja de volumen sin afectar a los SFX, y set_volumen_sfx(0.0) deja los efectos en silencio mientras la música sigue sonando.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| La música se corta y reinicia al cambiar de escena | Pusiste el AudioStreamPlayer dentro de la escena del nivel. Muévelo a un Autoload. |
| La música no se repite: suena una vez y calla | El OGG se importó sin Loop. Selecciónalo, activa Loop en la pestaña Import y reimporta. |
| El SFX de moneda no se oye porque el nodo se libera antes | Llamaste a queue_free() sin esperar. Usa await sonido.finished antes de liberar. |
| "Invalid access to property 'stream'" | El nodo Audio no existe o el $Ruta está mal escrito. Verifica el nombre en el panel Scene. |
| Bajar el Master no separa música de efectos | Todos los sonidos van al mismo bus. Asigna cada player a Music o SFX en su Inspector. |
| El WAV se oye recortado o con clic | Se importó con Loop activado. Desactiva Loop para SFX cortos. |
❓ ¿Cuándo uso AudioStreamPlayer2D en lugar del normal? Cuando quieres que el sonido dependa de la posición en el mundo: un enemigo lejano suena más flojo. Para música y UI usa el AudioStreamPlayer global.
❓ ¿Por qué WAV para efectos y OGG para música? El WAV carga al instante y es perfecto para sonidos cortos y frecuentes; el OGG está comprimido y ahorra mucho espacio en pistas largas de música.
❓ ¿Qué es exactamente un bus de audio? Es un canal intermedio: agrupas varios sonidos en él (por ejemplo todos los SFX) y ajustas su volumen o efectos en conjunto antes de mezclarlos en el Master.
❓ ¿Por qué la música va en un Autoload? Porque un Autoload se instancia una sola vez y sobrevive a los cambios de escena, así la banda sonora no se reinicia cada vez que cargas un nivel nuevo.
Clase 040 - Menús, pausa y flujo de escenas