Skip to content

Sound Engine

The SoundEngine (Game.audio()) handles all sound effects, ambient background audio, and background music streaming. It natively supports .wav, .ogg, and .mp3 audio formats without external native C libraries via its built-in Java Sound SPI.

flowchart TD
 subgraph AudioSources["Audio Sources"]
 SFX["Sound Effects (.wav, .ogg, .mp3)"]
 Music["Music Tracks (.ogg, .mp3)"]
 Spatial["Positional Sounds (Point2D)"]
 end

 subgraph SoundEngine["Game.audio()"]
 Master["Master Volume (sfx_soundVolume)"]
 MusicBus["Music Volume (sfx_musicVolume)"]
 SpatialCalc["2D Spatial Attenuation (Listener Focus)"]
 end

 SFX --> Master
 Spatial --> SpatialCalc --> Master
 Music --> MusicBus

Playing Sound Effects

Global (Non-Positional) Sounds

Play interface sounds, notifications, or player feedback anywhere in the world:

// Play a loaded sound resource (.wav, .ogg, or .mp3)
Game.audio().playSound("button-click.wav");
Game.audio().playSound("coin.mp3");

// Play with loop control (false = play once)
Sound hitSound = Resources.sounds().get("hit.ogg");
Game.audio().playSound(hitSound, false);

// Play with loop control, audible range, and custom volume multiplier
Game.audio().playSound(hitSound, false, Game.audio().getMaxDistance(), 1.0f);

2D Positional & Spatial Audio

LITIENGINE calculates stereo panning and volume falloff automatically based on distance from the camera focus (or active player entity listener):

// Play an explosion at an entity's world position
Point2D explosionPoint = bossEnemy.getCenter();
Game.audio().playSound("explosion.wav", explosionPoint);

// Positional audio automatically fades as the camera moves farther away
Game.audio().playSound("waterfall.mp3", waterfallEntity.getLocation());

Background Music & Tracks

Music is streamed asynchronously to optimize memory usage:

// Play looping background music (.ogg or .mp3)
Game.audio().playMusic("overworld-theme.ogg");

// Stop or pause music
Game.audio().stopMusic();

// Switch tracks
Game.audio().playMusic("boss-theme.mp3");

Seamless Intro + Loop Music (IntroTrack)

A common requirement in game music (e.g. boss battles, stage themes) is playing an introductory fanfare once before transitioning seamlessly into a continuous loop:

import de.gurkenlabs.litiengine.sound.IntroTrack;
import de.gurkenlabs.litiengine.sound.Track;

// Plays "boss-intro.mp3" once, then seamlessly loops "boss-loop.mp3" forever
Track bossMusic = new IntroTrack("boss-intro.mp3", "boss-loop.mp3");
Game.audio().playMusic(bossMusic);

LITIENGINE provides three built-in Track implementations:

  • IntroTrack: Plays an introductory sound once, then transitions into a seamless infinite loop.
  • LoopedTrack: Continuously loops a sound resource.
  • SinglePlayTrack: Plays a sound track once from start to finish without looping.

Volume Control & Configuration

Adjust audio levels globally or connect them to in-game options sliders:

// Sound effects volume (0.0f to 1.0f)
Game.config().sound().setSoundVolume(0.8f);

// Background music volume (0.0f to 1.0f)
Game.config().sound().setMusicVolume(0.5f);

// Read current configured volumes
float currentSfxVolume = Game.config().sound().getSoundVolume();
float currentMusicVolume = Game.config().sound().getMusicVolume();

In config.properties:

sfx_soundVolume=0.8
sfx_musicVolume=0.5

See Also


2D Spatial Audio & Audio Channel Mastering

LITIENGINE's audio engine supports multi-bus volume controls and realistic 2D positional attenuation:

1. Volume Management

Separate Music (BGM) and Sound Effect (SFX) volumes in your audio settings:

src/main/java/com/example/game/audio/AudioManager.java
package com.example.game.audio;

import de.gurkenlabs.litiengine.Game;
import de.gurkenlabs.litiengine.sound.Sound;
import de.gurkenlabs.litiengine.sound.LoopedTrack;
import de.gurkenlabs.litiengine.resources.Resources;

public class AudioManager {
  public static void setSoundVolume(float volume) {
    Game.config().sound().setSoundVolume(Math.clamp(volume, 0.0f, 1.0f));
  }

  public static void setMusicVolume(float volume) {
    Game.config().sound().setMusicVolume(Math.clamp(volume, 0.0f, 1.0f));
  }

  public static void playMusic(String soundName) {
    Sound musicSound = Resources.sounds().get(soundName);
    if (musicSound != null) {
      Game.audio().playMusic(new LoopedTrack(musicSound));
    }
  }

  public static void playSound(String soundName) {
    Game.audio().playSound(soundName);
  }
}

2. Positional 2D Spatial Sound (Distance Attenuation)

Play audio centered at specific world coordinates or attached to moving entities. As the player moves away from the sound source, volume attenuates naturally:

// Play positional explosion sound originating from a barrel entity
Game.audio().playSound(
Resources.sounds().get("explosion.ogg"),
barrelEntity.getCenter(),
false // do not loop
);

// Continuous spatial hum originating from a generator prop
Game.audio().playSound(
Resources.sounds().get("generator_hum.ogg"),
generatorProp,
true // loop continuously
);

Spatial Sound Range

By default, LITIENGINE computes attenuation based on the distance between the sound origin and the active Camera center. Ensure your player entity is tracked by the camera using Game.world().camera().setFocus(player).