Skip to content

Sound Effects

Soumya Aggarwal edited this page Oct 7, 2026 · 4 revisions

Sound effects give feedback for player, enemy, weapon and environment actions. Sounds are played in response to events the game already fires (e.g. jump, hurt, chaseStart), so other teams' logic didn't need to change, only small hooks were added. All game audio also goes through a master volume set in the Settings menu.

Key Components

  • SoundEffects: Shared list of every gameplay sound (FILES), with load() / unload() to load the whole list and play(path, volume) to play a sound safely (does nothing if it isn't loaded).
  • PlayerSoundComponent: Added to the player in PlayerFactory. Listens to player events and plays jump, hurt, pickup, potion, rope swing and item switch sounds.
  • ChaseSoundComponent: Added to enemies in EnemyFactory. Plays a sound when the enemy starts chasing the player, at most once every 10 seconds. Takes the sound file and volume so each enemy can have its own sound.
  • GameVolume: Holds the master volume (0 to 1). Every sound is played at GameVolume.scale(volume) and every music track is set with GameVolume.setMusicVolume(music, volume), so the slider affects all audio and playing music updates straight away.
  • ButtonSound: Plays the UI click for buttons, waiting 0.35s before a screen change so the click isn't cut off.

Where sounds are loaded

SoundEffects.load() is called by both LevelsGameScreen (Levels 1-3) and SandboxGameArea, so every sound works in the levels and the sandbox. They are unloaded with SoundEffects.unload() when the screen or area is disposed.

Sound List

Sound File Plays when Volume Where
Jump jump.ogg jump event 0.5 PlayerSoundComponent
Player hurt hurt_player_1-4.wav hurt event, one of 4 picked at random 0.3 / 0.3 / 1.0 / 0.6 PlayerSoundComponent
Item pickup itempickup02.wav itemPickedUp 0.2 PlayerSoundComponent
Coin pickup itempick.wav goldPickedUp 0.2 PlayerSoundComponent
Potion (health/speed) Drink_01.wav then Drink_02.wav 0.45s later itemUsed with a health or speed potion 0.9 PlayerSoundComponent
Rope swing rope_swing.wav grappleSwing, at most once every 1.5s 1.0 PlayerSoundComponent
Item switch itemSwitch.wav inventorySelectionChanged 0.15 PlayerSoundComponent
Bow shot shoot.ogg an arrow is fired 1.0 BowComponent
Poison flask smash Bottle Break.wav thrown poison flask hits something 0.3 ArrowProjectileComponent
Skeleton laugh evil cyber laugh.wav skeleton warrior/archer starts chasing (10s cooldown) 0.15 ChaseSoundComponent
Vulture screech osprey.ogg vulture starts chasing (10s cooldown) 0.15 ChaseSoundComponent
Enemy death enemy_Death.wav enemy health reaches 0 (plays once) 0.4 EnemyDeathComponent
Crumbling platform rock_break.ogg repeats every 0.3s from when the player touches it, getting louder, then a final crack when it breaks 0.1 -> 0.6 CrumblingPlatformComponent
Level complete level_complete.wav triggerNextLevel 0.5 LevelsGameScreen
Button click Button_Sound_02.wav any button press 1.0 ButtonSound

Music volumes (before the master volume is applied): main menu 0.1, gameplay 0.05, pause menu 0.1, win 0.13, lose 0.4, cutscene 0.1, level areas 0.3, minigames 0.25-0.4.

Volume Setting

The Volume slider is in both settings menus (from the main menu and from the pause menu), under UI Scale.

  • Dragging the slider changes the volume straight away, including music that's already playing.
  • Pressing Apply saves it to settings.json through UserSettings (volume, default 1.0).
  • Leaving the menu without pressing Apply puts the volume back to the saved value.
  • UserSettings.applySettings() calls GameVolume.set(), so the saved volume is used as soon as the game starts.

Adding a New Sound

  1. Put the file in assets/sounds/. Use .ogg or a plain 16-bit PCM .wav. WAVs exported with extra metadata (e.g. a bext chunk) or 32-bit float WAVs can fail to load in libGDX, which stops the rest of the batch loading.
  2. Add the path to SoundEffects.FILES.
  3. Play it with SoundEffects.play("sounds/your_sound.wav", volume). If you play a Sound or Music directly, use GameVolume.scale(volume) for sounds and GameVolume.setMusicVolume(music, volume) for music, otherwise it will ignore the volume slider.
  4. For a sound tied to an enemy starting a chase, add new ChaseSoundComponent("sounds/your_sound.ogg", volume) to the enemy in EnemyFactory.

Class Diagram

classDiagram
  class Component
  class SoundEffects {
    +String[] FILES$
    +load(ResourceService)$
    +unload(ResourceService)$
    +play(String path, float volume)$
  }
  class GameVolume {
    -float volume$
    +get()$ float
    +set(float)$
    +scale(float)$ float
    +setMusicVolume(Music, float)$
  }
  class PlayerSoundComponent {
    -String[] HURT_SOUNDS$
    -float[] HURT_VOLUMES$
    -long lastRopeSwingTime
    +create()
    -playHurt()
    -playPotion(Object)
    -playRopeSwing()
  }
  class ChaseSoundComponent {
    -String soundPath
    -float volume
    -long lastPlayTime
    +create()
    -playChaseSound()
  }
  class EnemyDeathComponent
  class CrumblingPlatformComponent
  class ButtonSound
  class UserSettings
  class PlayerFactory
  class EnemyFactory
  class LevelsGameScreen
  class SandboxGameArea

  Component <|-- PlayerSoundComponent
  Component <|-- ChaseSoundComponent
  Component <|-- EnemyDeathComponent
  Component <|-- CrumblingPlatformComponent
  PlayerSoundComponent ..> SoundEffects : plays through
  EnemyDeathComponent ..> SoundEffects : plays through
  SoundEffects ..> GameVolume : scales volume
  ChaseSoundComponent ..> GameVolume : scales volume
  CrumblingPlatformComponent ..> GameVolume : scales volume
  ButtonSound ..> GameVolume : scales volume
  UserSettings ..> GameVolume : sets saved volume
  PlayerFactory ..> PlayerSoundComponent : adds to player
  EnemyFactory ..> ChaseSoundComponent : adds to enemies
  LevelsGameScreen ..> SoundEffects : loads
  SandboxGameArea ..> SoundEffects : loads
Loading

Sequence Diagrams

Player gets hurt

sequenceDiagram
  participant C as CombatStatsComponent
  participant P as PlayerSoundComponent
  participant S as SoundEffects
  participant V as GameVolume
  participant R as ResourceService
  C->>P: trigger "hurt"
  P->>P: pick random grunt (1-4)
  P->>S: play("hurt_player_n.wav", volume)
  S->>R: containsAsset / getAsset
  S->>V: scale(volume)
  V-->>S: volume x master volume
  S->>R: sound.play(scaled volume)
Loading

Enemy starts chasing

sequenceDiagram
  participant T as ChaseTask
  participant E as ChaseSoundComponent
  participant G as GameTime
  participant V as GameVolume
  T->>E: trigger "chaseStart"
  E->>G: getTime()
  alt last sound was under 10s ago
    E-->>E: do nothing
  else cooldown finished
    E->>V: scale(volume)
    E->>E: play laugh / screech, save time
  end
Loading

Changing the volume slider

sequenceDiagram
  participant U as Player
  participant M as SettingsMenuDisplay
  participant V as GameVolume
  participant S as UserSettings
  U->>M: drag Volume slider
  M->>V: set(value)
  V->>V: update all playing music
  U->>M: press Apply
  M->>S: settings.volume = value, save
  S->>V: set(saved volume)
Loading

Testing

See [Sound Effects Test Plan]

Sound Credits

File Source Author Licence
Bottle Break.wav Breaking Bottle (OpenGameArt) spookymodem CC-BY 3.0
enemy_Death.wav Goblin Death (OpenGameArt) spookymodem CC-BY 3.0
evil cyber laugh.wav Evil Cyber Laugh (OpenGameArt) AppPro CC0
osprey.ogg Osprey Sound (OpenGameArt) AntumDeluge CC-BY-SA 4.0
rock_break.ogg Breaking Rock (OpenGameArt) themightyglider CC0
shoot.ogg Bow & Arrow Shot (OpenGameArt) dorkster CC-BY-SA 3.0
level_complete.wav Win Sound 2 (OpenGameArt), clip 2-3 converted to 16-bit remaxim CC-BY-SA 3.0
hurt_player_1-4.wav Character damage and other physical exertion (Freesound), cut into 4 clips randbsoundbites CC0
itemSwitch.wav Switch Flip #1 (Freesound), trimmed to 0.15s IanStarGem CC0
rope_swing.wav hamp rope creaks (Freesound), 1.5s cut 6polnic CC0

Clone this wiki locally