Learn Godot 4 by Making a 2D Platformer — Part 22: Music & SFX
Tags: gamedev, programming, beginners, tutorial
Published: 2023-08-10 02:01:00

**You can find the links to the previous parts at the bottom of this tutorial.*

Music and sound effects can add a new dimension to your game. Imagine playing your favorite video game — now imagine it without sound. What impact would that have on your experience? Would it still be your favorite game? In this part, we’ll be adding the second last piece to our game, which is music and sound effects.

**In Godot, you have three primary options for playing audio:**

 1. **AudioStreamPlayer**: This is a general audio player suitable for playing music or any non-positional audio. Use this when you don’t need the audio to have a position in the world. For example, if you have background music or dialog music that should be played irrespective of the position of the characters or objects in the game, use AudioStreamPlayer.

 2. **AudioStreamPlayer2D**: This is designed for 2D games where you need positional audio. It stimulates the position of the sound in a 2D space and will make sounds quieter the further away they are from the listener (camera, usually). Use this when you are making a 2D game and you want the audio to have a position in your 2D world (e.g., a sound effect that occurs at a certain location on the screen).

 3. **AudioStreamPlayer3D**: Similar to AudioStreamPlayer2D, but for 3D games. It takes into account the position of the sound in three-dimensional space. Use this in 3D games when you want the sound to emanate from a specific location in the 3D world.

Throughout this tutorial, we will use our [AudioStreamPlayer](https://docs.godotengine.org/en/stable/classes/class_audiostreamplayer.html) node for constant stable sounds such as our Background music or Dialog music. We will use our [AudioStreamPlayer2D](https://docs.godotengine.org/en/stable/classes/class_audiostreamplayer2d.html#class-audiostreamplayer2d) node however for our sound effects — because we want some panning in the sound and we also want the sound loudness to depend on the location of the sound.

---

***WHAT YOU WILL LEARN IN THIS PART:***

* *How to work with the AudioStreamPlayer & AudioStreamPlayer2D node.*

---

In your project, you’ll see in your Assets directory that I already added a folder with Music in it for us to use. You are welcome to go and source your audio, but for our game, I’m going to be using those assets.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*7WT8YRHieO09lbq7CsKxsg.png)

## STEP 1: MUSIC

### **Background Music**

In your Player scene, add a new AudioStreamPlayer node. This will serve as the audio container for your background music when the game plays.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*KllYnAvK4kGeK6adtTdoxA.png)

Rename it to “BackgroundMusic”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*7jKRkfj6SR_NcT-1L5_TEA.png)

Since we’ll be adding numerous AudioStreamPlayer nodes, let’s organize them underneath a Node2D node renamed “Music”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*sEH7Lg3DvfGJ0X5A4SBTIQ.png)

Our background music will be the audio file “arguement-loop-27901.mp3”. Godot supports both *.wav* and *.mp3* audio extensions. We can assign this audio file to our BackgroundMusic node in the inspector Panel underneath the Stream property. You can drag this audio file into the property, or you can add it by clicking on it and assigning it via the Quick Load method.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*k7hkLTSRa9tq9Pm-u0-54w.png)

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*OF30_f_WSGE9Xr4pUrb3rw.png)

This audio file is already imported with its looping value enabled, so we don’t need to worry about it playing and then stopping once it reaches the end! If you need to use an audio file that isn’t preconfigured for looping, you can re-import it in your Import dock with looping enabled.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*Rlr7ZXY2MdLW-YuUzfQQrA.png)

To play this BackgroundMusic node, we can reference it in our code wherever we want it to play via the *[play()](https://docs.godotengine.org/en/stable/classes/class_audiostreamplayer.html#class-audiostreamplayer-method-play)* method. In our case, we want it to play when the Player enters the scene — which is when our level starts.

```python   
    ### Player.gd
    #older code
    
    func _ready():
        #older code
            
        #play background music
        $Music/BackgroundMusic.play()
```
Now if you run your scene and you start a level, the background music should play.

### **Pause Menu Music**

We also want our pause menu to play its track when the player presses the *ui_pause* input. When the pause button is pressed, we need to stop our background music and play our pause music.

Add a new AudioStreamPlayer node and rename it to “PauseMenuMusic”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*__qy4HzusdbaADtUOLKETw.png)

Assign the “8bit-music-for-game-68698.mp3” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*6BYyvSK1Slz5YI_-9l5i7A.png)

In our *input()* function, underneath our *ui_pause* conditional, we need to play this audio track.
```python
    ### Player.gd
    
    #older code
    
    #singular input captures
    func _input(event):
        #pause game
        if event.is_action_pressed("ui_pause"):
            #show menu
            $PauseMenu.visible = true
            #pause scene
            get_tree().paused = true
            #show cursor
            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 
            #play pause menu music
            $Music/BackgroundMusic.stop()
            $Music/PauseMenuMusic.play()
```
We also need to stop the pause menu music from playing when the player resumes the game because we need the background music to play again.
```python
    ### Player.gd
    
    #older code
    
    #resume game
    func _on_button_resume_pressed():
        #unpause scene
        get_tree().paused = false
        #hide menu
        $PauseMenu.visible = false
        #stop pause menu music
        $Music/BackgroundMusic.play()
        $Music/PauseMenuMusic.stop()
```
Now if you run your scene and you pause your game, your pause menu music should play. If you resume your game, your background music should play.

### **Game Over Music**

When our player dies, we need to stop our background music and play our death music. In your Player scene, add a new AudioStreamPlayer node and rename it to “GameOverMusic”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*2T0RbEuNPQecsd-bbURhQQ.png)

Assign the “kl-peach-game-over-iii-142453.mp3” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*J1nU5N5y8pqZgajkT3hDrg.png)

Let’s play it when the player dies. We also need to stop the background music from playing.
```python
    ### Player.gd
    
    #older code
    
    #reset our animation variables
    func _on_animated_sprite_2d_animation_finished():
        if attack_time_left <= 0:
            Global.is_attacking = false
        set_physics_process(true)
        is_hurt = false
        
        if $AnimatedSprite2D.animation == "death":
            # pause game
            get_tree().paused = true
            # show menu
            $GameOver/Menu.visible = true
            # make modular value visible
            $AnimationPlayer.play("ui_visibility")  
            #hide the player's UI 
            $UI.visible = false
            #get final values
            final_score_time_and_rating()
            # show player values
            $GameOver/Menu/Container/TimeCompleted/Value.text = str(Global.final_time)
            $GameOver/Menu/Container/Score/Value.text = str(Global.final_score)
            $GameOver/Menu/Container/Ranking/Value.text = str(Global.final_rating)
            #show cursor
            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 
            #play game over music
            $Music/BackgroundMusic.stop()
            $Music/GameOverMusic.play()
```
We also need to continue the background music when our player presses the restart button on our game over screen.
```python
    ### Player.gd
    
    #older code
    
    #restarts game
    func _on_restart_button_pressed():
        #hide menu
        $GameOver/Menu.visible = false
        # Restart current scene
        get_tree().reload_current_scene()
        if Global.get_current_level_number() > 1:
            #unpause scene
            get_tree().paused = false
        #start background music
        $Music/BackgroundMusic.play()
```
Now if you run your scene, your music should play when our game is over.

**If your music is too loud/soft for your taste, you can edit its Volume property to be lower or higher in the Inspector panel. You can test this by enabling and disabling the Playing property.*

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*s2UgrBi1gnwb77-GXCdGzw.png)

### **Main Menu Music**

We also need music to play in our MainMenu scene. Create a new Node2D node called “Music” and add an AudioStreamPlayer node to it which you should rename to “BackgroundMusic”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*F57Hyv5LL7_6LQDPiCoM3Q.png)

Assign the “8bit-music-for-game-68698.mp3” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*SOq2OXAobOsY32ufW90QJQ.png)

Let’s play it when the MainMenu node enters the scene.
```python
    ### MainMenu.gd
    
    extends CanvasLayer
    
    func _ready():
        #pause it by default 
        get_tree().paused = true
        #show cursor
        Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 
        #play background music
        $Music/BackgroundMusic.play()
```
Now if you run your scene, your background music should play when your MainMenu is open.

### **Level Up Music**

We also need music to play in our LevelDoor scene when the player enters its collision body. Create a new Node2D node called “Music” and add an AudioStreamPlayer node to it which you should rename to “LevelUpMusic”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*GxRLwA82uXuNQBSBd0ff_w.png)

Assign the “cool pigeon.wav” track to its Stream property. If you don’t like this audio, you can also use the “kl-peach-game-over-iii-142453.mp3” or “computer(turn on).wav” audio.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*sE4X31y8Bzzu7w_uccKeuw.png)

Let’s play it when the LevelDoor node collides with our player body.
```python
    ### LevelDoor.gd
    
    #older code
    
    func _on_body_entered(body):
        if body.name == "Player":
            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 
            # pause game
            get_tree().paused = true
            # show menu
            $UI/Menu.visible = true
            # make modular value visible
            $AnimationPlayer.play("ui_visibility")  
            #hide the player's UI 
            body.get_node("UI").visible = false 
            #get final values
            body.final_score_time_and_rating()
            # show player values
            $UI/Menu/Container/TimeCompleted/Value.text = str(Global.final_time)
            $UI/Menu/Container/Score/Value.text = str(Global.final_score)
            $UI/Menu/Container/Ranking/Value.text = str(Global.final_rating)
            #play music
            $Music/LevelUpMusic.play()
```
Now if you run your scene, your level-up music should play when your player reaches the door.

## **STEP 2: SFX**

### **Jump SFX**

When our player jumps, we want to play a jumping sound effect. In your Player scene, add a new AudioStreamPlayer2D node and rename it to “JumpSFX”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2820/1*E_2Sh6OrDoPeNPc4hJj4hw.png)

Assign the “jump.wav” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*mSuOXI7cXdlejaxJGqVcsA.png)

In our *input()* function, underneath our *ui_jump* conditional, we need to play this audio track.
```python
    ### Player.gd
    
    #older code
    
    #singular input captures
    func _input(event):
        #older code
        #on jump
        if event.is_action_pressed("ui_jump") and is_on_floor():
            velocity.y = jump_height
            $AnimatedSprite2D.play("jump")
            #sfx
            $Music/JumpSFX.play()
```
You can also play this if your player is climbing ladders.
```python
    ### Player.gd
    
    #older code
    
    #singular input captures
    func _input(event):
        #older code
        #on climbing ladders
        if Global.is_climbing == true:
            if Input.is_action_pressed("ui_up"):
                $AnimatedSprite2D.play("climb") 
                gravity = 100
                velocity.y = -160
                Global.is_jumping = true
                $Music/JumpSFX.play()
```
Now if you run your scene, your sfx should play when your player jumps or climbs.

### **Damage SFX**

When our player gets damaged, we want to play a damaged sound effect. In your Player scene, add a new AudioStreamPlayer2D node and rename it to “DamageSFX”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*D5MzXNadZ8a4t68XpEfJHg.png)

Assign the “embarrassed.wav” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*lhIam6yqNaGGvZEdPJaxVw.png)

In our *take_damage()* function, we need to play this audio track.
```python
    ### Player.gd
    #older code
    
    # takes damage & death
    func take_damage():
        #deduct and update lives    
        if lives > 0 and Global.can_hurt == true:
            lives = lives - 1
            update_lives.emit(lives, max_lives)
            #play damage animation
            $AnimatedSprite2D.play("damage")
            #allows animation to play
            set_physics_process(false)
            is_hurt = true
            #decrease score
            decrease_score(10)
            $Music/DamageSFX.play()
        #death
        if lives <= 0:
            $AnimatedSprite2D.play("death")
```
Now if you run your scene, your sfx should play when your player gets hurt.

### **Pickup SFX**

When our player picks up any one of our pickups, we want to play a different sound. In your Player scene, add three new AudioStreamPlayer2D nodes and rename them to “ScoreSFX”, “BoostSFX”, and “HealthSFX”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*UJw87xfMvF8Myo6StyNMoQ.png)

Assign the “score.wav” track to the ScoreSFX’s Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*5GCRXwK5HmEAHnK9_pDvwA.png)

Assign the “boost.wav” track to the BoostSFX’s Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*x4bs5-KQoZQ4QhJ7AAwlcg.png)

Assign the “upgrade.wav” track to the HealthSFX’s Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*A6leDKei64uLIEz7tiyt5g.png)

In our *add_pickup()* function, we need to play these audio tracks.
```python
    ### Player.gd
    
    #older code
    
    #adds pickups to our player and updates our lives/attack boosts
    func add_pickup(pickup):
        #increases life count if we don't have 3 lives already
        if pickup == Global.Pickups.HEALTH:
            if lives < max_lives:
                lives += 1
                update_lives.emit(lives, max_lives)
            $Music/HealthSFX.play()
                
        #temporarily allows us to destroy boxes/bombs
        if pickup == Global.Pickups.ATTACK:
            Global.is_attacking = true
            $Music/BoostSFX.play()
            
        #increases our player's score
        if pickup == Global.Pickups.SCORE:
            increase_score(1000)
            $Music/ScoreSFX.play()
```
Now if you run your scene, your sfx should play when your player runs through the pickups.

### **Attack SFX**

When our player presses their ui_attack input, we want an attack SFX to play. In your Player scene, add a new AudioStreamPlayer2D node and rename it to “AttackSFX”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*m_HCGCC6bCjl1eIDVQle_g.png)

Assign the “attack variation.wav” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*0in1ajmBU-2aWHZON2Ss4w.png)

In our *input()* function, underneath our *ui_attack* conditional, we need to play this audio track.
```python
    ### Player.gd
    
    #older code
    
    #singular input captures
    func _input(event):
        #pause game
        if event.is_action_pressed("ui_pause"):
            #show menu
            $PauseMenu.visible = true
            #pause scene
            get_tree().paused = true
            #show cursor
            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 
            #play pause menu music
            $Music/BackgroundMusic.stop()
            $Music/PauseMenuMusic.play()
            
        #on attack
        if Input.is_action_just_pressed("ui_attack"):
            if Global.is_attacking == true:
                $AnimatedSprite2D.play("attack")
                $Music/AttackSFX.play()
```
Now if you run your scene, your sfx should play when your player attacks when their attack boost is active.

### **IncreaseScore SFX**

When our increases their score, we want the game to be notified via a soundtrack. In your Player scene, add a new AudioStreamPlayer2D node and rename it to “IncreaseScoreSFX”.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*ZmMKtXTEW6eTXyEgcbZw3w.png)

Assign the “Pickup Coin.wav” track to its Stream property.

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/1*uKGeOVSUzqq68g4MC_UDcQ.png)

In our *increase_score()* function, we need to play this audio track.
```python
    ### Player.gd
    
    #older code
    
    func increase_score(score_count):
        score += score_count
        update_score.emit(score)
        $Music/IncreaseScoreSFX.play()
```
Now if you run your scene, your sfx should play when your player ups their score.

Your code should look like [this](https://github.com/christinec-dev/CastleClimbersParts/tree/main/Part22).

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/3840/1*HMM8pUDQ7zTFGXcWWWYOUw.png)

I challenge you to go ahead and add more SFX if you’d like. Maybe play a sound if the player presses on a button, or when the Box and Bomb hits the Wall collisions. I’m going to stop here for now, since this is a good base. In the next part, we’ll be adding our particle effects to our game when our game. Now would be a good time to save your project and make a backup of your project so that you can revert to this part if any game-breaking errors occur. Go back and revise what you’ve learned before you continue with the series, and once you’re ready, I’ll see you in the next part!

---

## Next Part to the Tutorial Series

The tutorial series has 24 chapters. I’ll be posting all of the chapters in sectional daily parts over the next couple of weeks. You can find the updated list of the tutorial links for all 24 parts of this series on my [GitBook](https://oops-i-devd.gitbook.io/christinedevs/godot-tutorials/castle-climbers/tutorial). If you don’t see a link added to a part yet, then that means that it hasn’t been posted yet. Also, if there are any future [updates ](https://oops-i-devd.gitbook.io/christinedevs/communication/updates-and-notifications)to the series, my GitBook would be the place where you can keep up-to-date with everything!

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/0*TLFhoNqnjMYLWAGA.png)

---

## Support the Series & Gain Early Access!

If you like this series and would like to support me, you could [donate](https://ko-fi.com/christinedevs) any amount to my KoFi shop or you could [purchase the offline PDF](https://ko-fi.com/s/75433f1d4b) that has the entire series in one on-the-go booklet!

The booklet gives you lifelong access to the full, offline version of the “**Learn Godot 4 by Making a 2D Platformer**” PDF booklet. This is a 451-page document that contains all the tutorials of this series in a sequenced format, plus you get dedicated help from me if you ever get stuck or need advice. This means you don’t have to wait for me to release the next part of the tutorial series on Dev.to or Medium. You can just move on and continue the tutorial at your own pace — anytime and anywhere!

![Godot 2D Platformer](https://cdn-images-1.medium.com/max/2000/0*S6n1i41QDrVlLJUy.png)

*This book will be updated continuously to fix newly discovered bugs, or to fix compatibility issues with newer versions of Godot 4.*