Episode ini menyelami audio: AudioStreamPlayer beserta varian 2D dan 3D, cara menata background music dan sound effect, memahami audio buses, volume control, pitch shifting, efek audio seperti reverb, serta strategi integrasi audio yang hemat performa.

Di episode 9 kalian membereskan state dan persistence — data yang tersimpan rapi. Tapi ada satu elemen yang sering dianggap remeh padahal setengah dari pengalaman pemain: suara. Coba matikan suara saat menekan tombol, melompat, atau terkena musuh — game terasa kosong dan mati. Episode 10 ini membahas Audio & Sound Design dari sisi teknis: bagaimana Godot memainkan, mencampur, dan memproses audio.
Roadmap episode 10: kita mulai dari AudioStreamPlayer dan varian spatial 2D/3D, membedakan peran background music dan sound effect, memahami audio buses sebagai jalur pencampur, mengatur volume dan pitch, menerapkan audio effects seperti reverb, lalu menutupnya dengan strategi integrasi dan pertimbangan performa.
Node paling fundamental adalah AudioStreamPlayer. Ia memainkan satu audio stream pada posisi global — tidak peduli dari mana suara itu datang. Cukup isi properti stream dengan file audio (.wav, .ogg, .mp3) dan panggil play():
extends AudioStreamPlayer
func _ready() -> void:
stream = preload("res://audio/sfx/jump.wav")
volume_db = -6.0
func play_jump() -> void:
play()volume_db diukur dalam desibel: 0.0 adalah volume asli file, nilai negatif memperkecil, positif memperbesar hingga 0.0 adalah batas atas praktis. Untuk efek suara pendek yang sering dipicu berulang kali, godot membutuhkan beberapa instance agar tidak saling memotong — pola yang akan kita bahas di bagian performa.
Audio untuk pemutar global seperti musik latar cukup satu node AudioStreamPlayer yang diputar sekali dan dibiarkan mengulang. Untuk itu, stream file bisa diatur loop di editor, atau lewat properti pada AudioStreamOggVorbis dan AudioStreamWAV.
Suara yang sama tidak selalu terdengar sama. Kalau sebuah objek berada di sebelah kiri pemain, masuk akal jika suaranya terdengar dari kiri. Itulah fungsi AudioStreamPlayer2D dan AudioStreamPlayer3D: suara yang berposisi di dunia dan dihitung secara spatial.
AudioStreamPlayer2D menghitung volume dan panning berdasarkan jarak serta posisi relatif terhadap pendengar (biasanya kamera atau player). Properti pentingnya:
max_distance — jarak di mana suara tak lagi terdengar.attenuation — seberapa cepat volume mengecil seiring jarak.autoplay — otomatis main saat scene dimuat.extends AudioStreamPlayer2D
func _ready() -> void:
max_distance = 800.0
attenuation = 1.5
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
play()Untuk 3D, AudioStreamPlayer3D menambahkan perhitungan 3D penuh dengan properti unit_size, max_db, dan area_mask. Intuisi yang sama berlaku: node ditempel pada objek dunia, dan Godot menghitung volume berdasarkan jarak ke pendengar. Jika game kalian sepenuhnya 2D dan kamera selalu di tengah, AudioStreamPlayer biasa lebih hemat.
Ada dua kelas suara yang membutuhkan perlakuan berbeda: BGM (background music) dan SFX (sound effects).
Perbedaan teknisnya penting: untuk BGM, gunakan format terkompresi seperti Ogg Vorbis dan set stream mode menjadi stream (bukan sample). Untuk SFX, format WAV mentah memberi latensi terendah. Godot mengimpor WAV sebagai data sample di memori, sementara Ogg dibaca bertahap — ini yang membuat SFX instan dan BGM hemat memori.
extends AudioStreamPlayer
func _ready() -> void:
play()
func fade_out(duration: float) -> void:
var tween := create_tween()
tween.tween_property(self, "volume_db", -80.0, duration)
tween.tween_callback(stop)fade_out di atas memakai Tween (pola episode 6) untuk memperhalus pergantian lagu — pematian mendadak selalu terdengar kasar. Prinsip desain: musik menetapkan mood dan ritme, SFX menyampaikan informasi (langkah, kemenangan, bahaya). Keduanya harus menopang gameplay, bukan bersaing dengannya.
Membayangkan semua suara dicampur dalam satu jalur? Itu hanya akan membuat game mustahil disetel. Jawabannya adalah audio buses. Bus adalah jalur campuran terpisah yang bisa kalian atur volume dan efeknya secara independen. Godot menyediakan bus master bawaan, dan kalian bebas menambah bus lain — misal Music, SFX, dan UI.
Di editor, panel Audio membuka bus layout: buat bus, lalu arahkan setiap AudioStreamPlayer ke bus yang tepat lewat properti bus. Dari script, kalian mengontrol bus dengan AudioServer:
extends Node
func set_bus_volume(bus_name: String, value: float) -> void:
var idx := AudioServer.get_bus_index(bus_name)
AudioServer.set_bus_volume_db(idx, linear_to_db(value))Fungsi linear_to_db{gdscript} mengubah nilai slider linear 0.0 sampai 1.0 menjadi desibel yang sesuai telinga — ini pasangan sempurna untuk HSlider di settings game yang sudah kalian buat di episode 8. Dengan bus terpisah, pemain bisa mematikan musik tapi tetap mendengar efek — fitur yang hampir selalu diminta di game.
Info
Bus layout tersimpan di file resource dan juga bisa dimuat otomatis dari autoload. Untuk game dengan banyak scene, tempatkan bus layout global dan pastikan semua player memakai nama bus yang konsisten — misal bus Music hanya diisi BGM, bus SFX hanya diisi efek.
Selain volume, ada satu parameter yang mengubah karakter suara secara drastis: pitch. pitch_scale mempercepat atau memperlambat playback. Nilai 1.0 adalah normal, 0.5 terdengar berat dan lambat, 2.0 terdengar cempreng dan cepat. Teknik ini dipakai untuk variasi SFX — satu file langkah bisa menghasilkan banyak nuansa hanya dengan menggeser pitch sedikit.
extends AudioStreamPlayer
func play_with_variation(base_pitch: float = 1.0) -> void:
pitch_scale = base_pitch + randf_range(-0.1, 0.1)
play()Variasi pitch kecil inilah yang membuat langkah kaki tidak terdengar seperti mesin yang sama persis berulang-ulang — sentuhan kecil berharga besar. Lalu ada audio effects yang dipasang pada bus: AudioEffectReverb untuk ruangan bergema, AudioEffectDistortion untuk suara robotik, AudioEffectCompressor untuk meratakan dinamika. Efek dipasang pada bus, sehingga semua suara yang melewati bus itu terpengaruh:
extends Node
func _ready() -> void:
var idx := AudioServer.get_bus_index("SFX")
var effect := AudioEffectReverb.new()
AudioServer.add_bus_effect(idx, effect)Menambahkan effect dari script memberi kalian kontrol dinamis: gua dalam game bisa mengaktifkan reverb saat pemain memasukinya, lalu menonaktifkannya di ruang terbuka. Hanya ingat: setiap effect menambah beban pemrosesan audio, jadi jangan menumpuk effect tanpa tujuan.
Audio yang dipasang asal-asalan adalah penyebab lag yang tak terduga. Beberapa aturan yang menjaga performa tetap prima:
AudioStreamPlayer sendiri — memori dan node tree membengkak.AudioStreamPlayer (misal 8 buah) dan putar SFX pada yang sedang idle; pola ini disebut sound pool.extends Node
@onready var players: Array[AudioStreamPlayer] = []
func _ready() -> void:
for i in range(8):
var player := AudioStreamPlayer.new()
add_child(player)
players.append(player)
func play_sfx(stream: AudioStream) -> void:
for player in players:
if not player.playing:
player.stream = stream
player.play()
returnpreload; biarkan BGM di-stream dari disk agar RAM tidak meledak.process_mode dan bus masing-masing.Dengan pola pool, 50 ledakan dalam satu detik hanya memakai 8 player yang bergantian, bukan 50 node baru. Hasilnya suara tetap kaya tanpa membunuh frame rate.
Episode 10 membekali kalian dengan seluruh sisi teknis audio: AudioStreamPlayer untuk suara global, varian 2D/3D untuk suara spasial, pembagian peran BGM dan SFX, audio buses sebagai jalur pencampur, kontrol volume dan pitch, audio effects seperti reverb, sampai pola integrasi yang menjaga performa.
Inti yang harus dibawa pulang:
AudioStreamPlayer2D/3D memberi kesan posisi — volumenya ditentukan jarak ke pendengar.Music dan SFX agar pemain bisa menyetelnya terpisah.linear_to_db saat mengatur volume bus.pitch_scale dengan variasi kecil membuat SFX berulang terasa alami.Di episode 11 kalian akan menguasai cara pemain berbicara ke game: Input & Controls. Kita akan merancang input map berbasis action, mendukung keyboard, mouse, touch, dan gamepad, membedakan penanganan input UI versus input game, sampai pola virtual controls untuk mobile. Sampai jumpa di dunia input!