Repository navigation
Sound Effects
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.
-
SoundEffects: Shared list of every gameplay sound (FILES), withload()/unload()to load the whole list andplay(path, volume)to play a sound safely (does nothing if it isn't loaded). -
PlayerSoundComponent: Added to the player inPlayerFactory. Listens to player events and plays jump, hurt, pickup, potion, rope swing and item switch sounds. -
ChaseSoundComponent: Added to enemies inEnemyFactory. 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 atGameVolume.scale(volume)and every music track is set withGameVolume.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.
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 | 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.
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.jsonthroughUserSettings(volume, default 1.0). - Leaving the menu without pressing Apply puts the volume back to the saved value.
-
UserSettings.applySettings()callsGameVolume.set(), so the saved volume is used as soon as the game starts.
- Put the file in
assets/sounds/. Use.oggor a plain 16-bit PCM.wav. WAVs exported with extra metadata (e.g. abextchunk) or 32-bit float WAVs can fail to load in libGDX, which stops the rest of the batch loading. - Add the path to
SoundEffects.FILES. - Play it with
SoundEffects.play("sounds/your_sound.wav", volume). If you play aSoundorMusicdirectly, useGameVolume.scale(volume)for sounds andGameVolume.setMusicVolume(music, volume)for music, otherwise it will ignore the volume slider. - For a sound tied to an enemy starting a chase, add
new ChaseSoundComponent("sounds/your_sound.ogg", volume)to the enemy inEnemyFactory.
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
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)
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
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)
See [Sound Effects Test Plan]
| 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 |
Entities and Components
Input Handling
Arrow Selection Wheel Arrow Selection Wheel — Sprint 3