Immersive game sounds and background music play a huge role in determining the success or failure of any game. In this tutorial, we will learn how to add sounds and music to our game using the AudioStream family of nodes.
Godot’s audio system
To reproduce sounds, Godot’s audio system uses elements called audio buses. An audio bus is a “place” through which audio is channeled. A bus can modify audio data by applying one or more effect processors and then route it to another bus.
Audio buses can be found in the bottom panel of the Godot editor:

By default, there is only one audio bus, the master bus (it’s always the leftmost one). This is the bus that outputs the audio to your speakers.
The other audio buses can be flexibly routed to other buses. Routing can only happens from buses on the right to buses further to the left, to avoids infinite loops.
When using a node for audio playback, you must choose which bus to send the audio to (by default it’s the master bus). For our simple game, we will only use the master bus.
Godot’s audio interface mainly uses the decibel scale, the same used by audio professionals. The decibel (dB) scale is a relative (logarithmic) scale. For every 6 dB, sound amplitude doubles or halves.
Import sounds
Click the button below to download all the sound assets we need for the game.
Download “SimpleRPG Sounds and Musics”
music_sounds.zip – Downloaded 3628 times – 2.56 MBContains music ©2019 Joshua McLean (mrjoshuamclean.com)
Licensed under Creative Commons Attribution 4.0 International
In the FileSystem panel, create a new folder called Sounds and import into it all the downloaded audio files.
Background music
In the main game scene, add an AudioStreamPlayer node to Player, and rename it Music.
The AudioStream family of nodes is used to send sounds to audio buses. AudioStreamPlayer is the standard, non-positional stream player. The sound stream can come from many places, but is most commonly loaded from the filesystem. Godot supports WAV (.wav) and Ogg Vorbis (.ogg) audio files.
Drag the mountain-trials.ogg file to the Stream property in the Inspector, then turn on Autoplay to play the music when the game starts. You can adjust the volume of the music to your taste using the Volume Db property. For background music, I set it to -6 Db. Finally, set Pause → Mode to Process, so that the music doesn’t stop playing when the game is paused.

The music will be looped, because by default the Ogg Vorbis files are imported with the Loop property activated.

Add another AudioStreamPlayer to Player and rename it to MusicGameOver and drag the night-chip.ogg file to the Stream property in the Inspector. We will use this node to play the game over music when the player dies.
Now open the Player.gd script and edit the hit() function to stop the background music and play the game over music:
func hit(damage):
health -= damage
emit_signal("player_stats_changed", self)
if health <= 0:
set_process(false)
$AnimationPlayer.play("Game Over")
$Music.stop()
$MusicGameOver.play()
else:
$AnimationPlayer.play("Hit")
Stopping and playing a sound is very simple: just call the stop() and play() functions of AudioStreamPlayer.
This is what will happen when the player dies:
Attack sound
Let’s add the sound effects starting from the player’s attack. Add an AudioStreamPlayer2D node to Player and rename it SoundAttack.
AudioStreamPlayer2D is a variant of AudioStreamPlayer that emits sound in a 2D positional environment. When the node is close to the left of the screen, the panning will go left. When close to the right side, it will go right.
Drag the attack.wav file to the Stream property in the Inspector and set Volume Db to 6. Unlike .ogg files, by default .wav files are not looped.
Open the Player.gd script and go to the _input() function. In the code that handles the attack input action, we must add the code to play the sound, immediately after the code that plays the attack animation:
if event.is_action_pressed("attack"):
# Check if player can attack
var now = OS.get_ticks_msec()
if now >= next_attack_time:
# What's the target?
var target = $RayCast2D.get_collider()
if target != null:
if target.name.find("Skeleton") >= 0:
# Skeleton hit!
target.hit(attack_damage)
if target.is_in_group("NPCs"):
# Talk to NPC
target.talk()
return
# Play attack animation
attack_playing = true
var animation = get_animation_direction(last_direction) + "_attack"
$Sprite.play(animation)
# Play attack sound
$SoundAttack.play()
# Add cooldown time to current time
next_attack_time = now + attack_cooldown_time
Now open the Skeleton.tscn scene and add an AudioStreamPlayer2D to the Skeleton node. Rename it SoundAttack. Drag the attack.wav file to the Stream property in the Inspector and set Volume Db to 6.
Open the Skeleton.gd script and insert in the _on_AnimatedSprite_frame_changed() function the code to play the attack sound:
func _on_AnimatedSprite_frame_changed():
if $AnimatedSprite.animation.ends_with("_attack") and $AnimatedSprite.frame == 1:
var target = $RayCast2D.get_collider()
if target != null and target.name == "Player" and player.health > 0:
player.hit(attack_damage)
# Play attack sound
$SoundAttack.play()
Since the attack animation of the skeleton is slower, the sound is reproduced at frame 1 of the animation for better audio/video sync.
Skeleton death
Add another AudioStreamPlayer2D to the Skeleton node and rename it SoundDeath. Drag the death.wav file to the Stream property and set Volume Db to 6.
In the Skeleton.gd script, edit the hit() function to play the death sound when the skeleton die:
func hit(damage):
health -= damage
if health > 0:
$AnimationPlayer.play("Hit")
else:
$Timer.stop()
direction = Vector2.ZERO
set_process(false)
other_animation_playing = true
$AnimatedSprite.play("death")
emit_signal("death")
# Play death sound
$SoundDeath.play()
# 80% probability to drop a potion on death
if rng.randf() <= 0.8:
var potion = potion_scene.instance()
potion.type = rng.randi() % 2
get_tree().root.get_node("Root").add_child(potion)
potion.position = position
# Add XP to player
player.add_xp(25)
This is the result after adding the attack and death sounds:
Fireball sounds
Go back to the main scene, add an AudioStreamPlayer2D node to Player and rename it SoundFireball. Drag the fireball.wav file to the Stream property and set Volume Db to 6.
Open the Player.gd script and go to the _input() function. In the code that handles the fireball input action, add the code to play the fireball sound, immediately after the code that plays the fireball animation:
elif event.is_action_pressed("fireball"):
var now = OS.get_ticks_msec()
if mana >= 25 and now >= next_fireball_time:
# Update mana
mana = mana - 25
emit_signal("player_stats_changed", self)
# Play fireball animation
attack_playing = true
var animation = get_animation_direction(last_direction) + "_fireball"
$Sprite.play(animation)
# Play fireball sound
$SoundFireball.play()
# Add cooldown time to current time
next_fireball_time = now + fireball_cooldown_time
Now, open the Fireball.tscn scene and add an AudioStreamPlayer2D to the Fireball node. Rename it SoundExplosion. Drag the explosion.wav file to the Stream property and set Volume Db to 6.
Go the Fireball.gd script. At the end of the _on_Fireball_body_entered() function add this code:
# Play explosion sound
$SoundExplosion.play()
Picking up objects and using potions
Return to the main scene and add another AudioStreamPlayer2D to Player. Rename it SoundObject. Drag the object.wav file to the Stream property and set Volume Db to 6.
Now open the Player.gd script and in the _input() function edit the code that handles the potion drinking like this:
elif event.is_action_pressed("drink_health"):
if health_potions > 0:
health_potions = health_potions - 1
health = min(health + 50, health_max)
emit_signal("player_stats_changed", self)
# Play sound
$SoundObject.play()
elif event.is_action_pressed("drink_mana"):
if mana_potions > 0:
mana_potions = mana_potions - 1
mana = min(mana + 50, mana_max)
emit_signal("player_stats_changed", self)
# Play sound
$SoundObject.play()
Then, add at the end of the add_potion() function the code to play the sound when a potion is added to the inventory:
# Play sound
$SoundObject.play()
We want to play the same sound when we pick up the necklace needed to complete Fiona’s quest. Let’s see a different way to handle the reproductions of this sound.
Open the Necklace.tscn scene. Add an AudioStreamPlayer2D to the Necklace node and rename it SoundObject. Drag object.wav to the Stream property and set Volume Db to 6.
Now, go to the Necklace.gd script.
The most obvious thing we can do is to add $SoundObject.play() to the _on_Necklace_body_entered() function to play the sound. But if you try to do this, the sound will not play!
This happens because at the end of this function, the Necklace node is deleted from the scene tree. As a result, the SoundObject node is also deleted and doesn’t play the sound. So, we’ll have to connect to the finished() signal of the SoundObject node to delete Necklace only after the sound has finished playing.
Connect the finished() signal of SoundObject to Necklace, and move the queue_delete() call to the _on_SoundObject_finished() function:
func _on_SoundObject_finished():
get_tree().queue_delete(self)
Finally, edit the _on_Necklace_body_entered() function to play the sound:
func _on_Necklace_body_entered(body):
if body.name == "Player":
$SoundObject.play()
hide()
fiona.necklace_found = true
Now that Necklace is not deleted immediately, it would remain visible until the sound ends. To solve this problem, we make it invisible by calling the hide() function.
Level up sound
Now we just have to add one last sound: the sound that notify us of the level advancement of the player.
Go back to the main scene and add an AudioStreamPlayer to the LevelPopup node. Rename it SoundLevelUp. Drag level_up.wav to the Stream property and set Volume Db to 6.
Open the LevelPopup.gd script and at the end of the _on_Player_player_level_up() function add this code:
# Play level up sound
$SoundLevelUp.play()
Conclusions
In this simple tutorial we learned the basics of Godot’s audio system and how to add music and sounds to our game using the nodes of the AudioStream family.
You can try the game with sounds and music included by clicking here:
In the next tutorial we’ll add a menu to restart and quit the game.
10 Comments
James · February 10, 2020 at 11:27 am
Wow! This is great Davide Pesce.
I learnt a lot from these tutorial. Can’t wait for the next one. Thanks for doing this.
Continue the hard work this is really helping some of us. 🙂
Thanks! 🙂
Anastasia · March 28, 2020 at 1:58 pm
Hi there!
Great tutorial as always! Didnt have any problems this time ( ;
I just dropped in to say that i’d be very cool if you could show us how we can have a sound that plays when the NPC is talking, like a ‘voice’ kind of
Again really liked this one, you’re doing a great job
Davide Pesce · March 29, 2020 at 1:27 pm
Hi Anastasia!
it’s very easy to add a sound effect when the NPC speaks:
You can also create multiple AudioStreamPlayer2D nodes and use different sounds depending on what the NPC says (for example to show different emotions)
Anastasia · March 29, 2020 at 4:58 pm
Thanks so much!
Thomas · November 13, 2020 at 10:15 pm
Hello,
thank you very much for this tutorial!
“Only” a small game, but creating makes a lot of fun.
It wins a lot with these sounds, wich beamed me back to my youth in the 80ies, playing 8Bit games with exactly these sound.
Thanks a lot, you are a great teacher!
Thomas
Davide Pesce · November 21, 2020 at 1:33 pm
Thank you Thomas! 🙂
gus · November 16, 2020 at 9:04 pm
Hi Davide, thanks for the tutorial. I have a question, ¿is ti possible to import ambisonic files? as a way to create 3d sound
Davide Pesce · November 21, 2020 at 1:36 pm
Hi Gus, Godot only supports OGG and WAV audio formats.
shaun · March 3, 2021 at 1:48 am
Ambisonic format means the way it was encoded. They can be any type of container, including wav. I think Gus was asking if Godot has a built in decoder such as Unity or Unreal. Based on their documents, it doesn’t look like they don’t support it natively yet.
BlackHole · February 16, 2021 at 10:14 am
Holy moly I wasn’t exactly following this tutorial I just wanted to know how the sound effects worked because I was having a problem and just stumbled across this page from google and this was literally the only thing I found which was this simple and straight to the point.
keep up the good work
Comments are closed.