Try out our latest games now! →
iconSUPERMATRIX STUDIO
ProjectsToolsGuidesBlogNewsPlay Now!
iconSUPERMATRIX STUDIO
Play Now!
  • Home
  • Projects
  • Tools
  • About
  • Blogs
  • News

Socials

  • Twitter
  • GitHub
  • LinkedIn

Game Polish: Audio, Screen Shake, and Main Menu

Game Polish: Audio, Screen Shake, and Main Menu
Instructor

NoFace

Mentor

Welcome to the fifth and final lesson of our series. The core mechanics and game loop are functional, but the game still feels like a prototype. Game "juice" is what separates a tutorial project from a finished product.

In this module, we will add audio feedback, a visceral screen shake when crashing, and a "Get Ready" state so the game doesn't instantly drop the bird upon opening.


1. Adding Audio Feedback#

Audio is crucial for player feedback. We need sounds for flapping, scoring, and crashing.

  1. In your Main scene, add three AudioStreamPlayer nodes (not 2D, as we want UI sounds to play at constant volume). Name them FlapSound, ScoreSound, and CrashSound.
  2. Drag your respective .wav or .ogg files from the res://Assets/ folder into the Stream property of each node.

Now, let's trigger them in Main.gd:

gdscript
@onready var score_sound: AudioStreamPlayer = $ScoreSound
@onready var crash_sound: AudioStreamPlayer = $CrashSound

func add_score() -> void:
	score += 1
	score_label.text = str(score)
	
	# Randomize pitch slightly for variety so the sound doesn't get annoying
	score_sound.pitch_scale = randf_range(0.9, 1.1)
	score_sound.play()

func _on_bird_crashed() -> void:
	crash_sound.play()
	# ... existing game over logic ...

(Remember to also trigger your FlapSound inside the Bird.gd script when the flap input is pressed!)


2. Screen Shake Component#

When the bird hits a pipe, we want the player to feel the impact. A quick camera shake is perfect for this.

  1. Add a Camera2D node to your Main scene and make it the Current camera.
  2. Attach a new script to the Camera2D named CameraShake.gd.
gdscript
extends Camera2D

var shake_intensity: float = 0.0
var shake_fade: float = 5.0

func apply_shake(intensity: float = 10.0) -> void:
	shake_intensity = intensity

func _process(delta: float) -> void:
	if shake_intensity > 0:
		# Apply random offset based on intensity
		offset = Vector2(randf_range(-1, 1), randf_range(-1, 1)) * shake_intensity
		
		# Fade out the shake over time
		shake_intensity = lerpf(shake_intensity, 0.0, shake_fade * delta)
	else:
		offset = Vector2.ZERO

Now, in your Main.gd script's _on_bird_crashed() function, simply call $Camera2D.apply_shake(15.0).


3. Creating the "Get Ready" State#

Right now, gravity applies immediately. We want the bird to hover until the player makes their first flap.

  1. In Bird.gd, add a boolean variable: var game_started: bool = false.
  2. Wrap the gravity logic in an if statement.
gdscript
func _physics_process(delta: float) -> void:
	# Only apply gravity if the game has started
	if not is_on_floor() and game_started:
		velocity.y += gravity * delta

	if Input.is_action_just_pressed("flap") and is_alive:
		game_started = true # First flap starts the game
		velocity.y = jump_velocity
		# ... play flap sound ...
  1. Back in Main.gd, you will also want to wait to start your SpawnTimer and the background shader until the bird emits a new started signal.

Congratulations! You have built a complete, polished 2D game in Godot 4. You can now take these fundamentals—state management, physics overrides, and shader manipulation—and apply them to much larger projects.

PreviousUI Integration, Game Over State, and Score Tracking

Explore More Lessons

Project Setup and 2D Physics Foundation

Completed

Infinite Scrolling Environment with Shaders

Completed

Procedural Pipe Generation and Collision Detection

Completed

UI Integration, Game Over State, and Score Tracking

Completed

Game Polish: Audio, Screen Shake, and Main Menu

Current Lesson

Supermatrix Studio

Building immersive, neon-drenched worlds.

Social
© 2026 Supermatrix Studio. All rights reserved.