TCJSGame Sound Class: Complete Reference Guide
Introduction to the Sound Class
TCJSGame's Sound Class provides simple yet powerful audio capabilities for your games. It wraps the HTML5 Audio API to handle sound effects, background music, and audio management with an easy-to-use interface.
🎵 Basic Sound Implementation
Creating Sound Objects
// Create sound effects
const jumpSound = new Sound("sounds/jump.wav");
const coinSound = new Sound("sounds/coin.mp3");
const explosionSound = new Sound("sounds/explosion.ogg");
// Create background music
const bgMusic = new Sound("music/background.mp3");
// Example: Preloading essential sounds
function preloadSounds() {
const sounds = {
jump: new Sound("sounds/jump.wav"),
hit: new Sound("sounds/hit.wav"),
victory: new Sound("sounds/victory.mp3"),
music: new Sound("music/game_theme.mp3")
};
return sounds;
}
const gameSounds = preloadSounds();
Basic Playback Control
// Play sounds
jumpSound.play();
coinSound.play();
// Stop sounds
bgMusic.stop();
explosionSound.stop();
// Example: Player jump with sound
function playerJump() {
if (player.gravitySpeed === 0) {
player.speedY = -12;
jumpSound.play();
}
}
// Example: Coin collection
function collectCoin(coin) {
coin.hide();
score += 10;
coinSound.play();
}
🎮 Advanced Audio Features
Looping Background Music
// While Sound class doesn't have built-in loop, you can implement it
class LoopingSound extends Sound {
constructor(src, loop = false) {
super(src);
this.loop = loop;
this.sound.loop = loop;
}
play() {
this.sound.currentTime = 0; // Reset to start
super.play();
}
}
// Usage
const backgroundMusic = new LoopingSound("music/background.mp3", true);
backgroundMusic.play();
// Alternative: Manual looping
function playBackgroundMusic() {
bgMusic.play();
bgMusic.sound.addEventListener('ended', function() {
this.currentTime = 0;
this.play();
}, false);
}
Volume Control
// Volume control (0.0 to 1.0)
jumpSound.sound.volume = 0.7; // 70% volume
bgMusic.sound.volume = 0.3; // 30% volume for background music
explosionSound.sound.volume = 1.0; // Full volume
// Example: Volume settings system
class AudioManager {
constructor() {
this.sounds = {};
this.masterVolume = 1.0;
this.musicVolume = 0.6;
this.sfxVolume = 0.8;
this.muted = false;
}
addSound(name, src, type = 'sfx') {
this.sounds[name] = {
sound: new Sound(src),
type: type
};
this.updateVolume(name);
}
play(name) {
if (!this.muted && this.sounds[name]) {
this.sounds[name].sound.play();
}
}
updateVolume(name) {
if (this.sounds[name]) {
const soundObj = this.sounds[name];
let volume = this.masterVolume;
if (soundObj.type === 'music') volume *= this.musicVolume;
if (soundObj.type === 'sfx') volume *= this.sfxVolume;
soundObj.sound.sound.volume = this.muted ? 0 : volume;
}
}
toggleMute() {
this.muted = !this.muted;
Object.keys(this.sounds).forEach(name => this.updateVolume(name));
}
}
// Usage
const audio = new AudioManager();
audio.addSound('jump', 'sounds/jump.wav', 'sfx');
audio.addSound('music', 'music/theme.mp3', 'music');
audio.play('jump');
🎯 Practical Game Examples
Platformer Sound System
class PlatformerAudio {
constructor() {
this.sounds = {
jump: new Sound("sounds/jump.wav"),
land: new Sound("sounds/land.wav"),
coin: new Sound("sounds/coin.wav"),
enemyHit: new Sound("sounds/enemy_hit.wav"),
playerHit: new Sound("sounds/player_hit.wav"),
levelComplete: new Sound("sounds/level_complete.wav"),
bgMusic: new Sound("music/background.mp3")
};
// Set volumes
this.sounds.bgMusic.sound.volume = 0.4;
this.sounds.jump.sound.volume = 0.7;
}
playJump() {
this.sounds.jump.play();
}
playLand() {
this.sounds.land.play();
}
playCoin() {
this.sounds.coin.play();
}
startBackgroundMusic() {
this.sounds.bgMusic.play();
// Implement looping
this.sounds.bgMusic.sound.addEventListener('ended', () => {
this.sounds.bgMusic.play();
});
}
stopBackgroundMusic() {
this.sounds.bgMusic.stop();
}
}
// Usage in game
const gameAudio = new PlatformerAudio();
function update() {
// Play jump sound when player jumps
if (display.keys[32] && player.gravitySpeed === 0) { // Spacebar
player.speedY = -12;
gameAudio.playJump();
}
// Play land sound when player hits ground
if (player.y >= display.canvas.height - player.height && player.gravitySpeed > 0) {
gameAudio.playLand();
}
}
Shooter Game Audio
class ShooterAudio {
constructor() {
this.sounds = {
laser: new Sound("sounds/laser.wav"),
explosion: new Sound("sounds/explosion.wav"),
powerup: new Sound("sounds/powerup.wav"),
shield: new Sound("sounds/shield.wav"),
gameOver: new Sound("sounds/game_over.wav"),
bgMusic: new Sound("music/space_theme.mp3")
};
}
playLaser() {
this.sounds.laser.play();
}
playExplosion() {
this.sounds.explosion.play();
}
playPowerup() {
this.sounds.powerup.play();
}
}
// Usage
const shooterAudio = new ShooterAudio();
function fireLaser() {
const laser = new Component(5, 15, "red", player.x, player.y, "rect");
laser.speedY = -10;
display.add(laser);
shooterAudio.playLaser();
}
function enemyDestroyed(enemy) {
enemy.hide();
score += 100;
shooterAudio.playExplosion();
}
🔧 Audio Management Systems
Sound Pool for Frequent Sounds
class SoundPool {
constructor(src, poolSize = 5) {
this.sounds = [];
this.currentIndex = 0;
// Create pool of sound instances
for (let i = 0; i < poolSize; i++) {
const sound = new Sound(src);
this.sounds.push(sound);
}
}
play() {
// Round-robin through sound instances to allow overlapping
this.sounds[this.currentIndex].play();
this.currentIndex = (this.currentIndex + 1) % this.sounds.length;
}
}
// Usage for frequent sounds like laser shots
const laserPool = new SoundPool("sounds/laser.wav", 3);
function rapidFire() {
// Can play multiple times quickly without cutting off previous sounds
laserPool.play();
}
Sequential Sound Playback
class SoundSequence {
constructor() {
this.sounds = [];
this.currentSound = 0;
this.playing = false;
}
addSound(sound, delay = 0) {
this.sounds.push({ sound, delay });
}
play() {
if (this.playing || this.sounds.length === 0) return;
this.playing = true;
this.currentSound = 0;
this.playNext();
}
playNext() {
if (this.currentSound >= this.sounds.length) {
this.playing = false;
return;
}
const { sound, delay } = this.sounds[this.currentSound];
setTimeout(() => {
sound.play();
this.currentSound++;
// Wait for sound to finish or use fixed delay
setTimeout(() => this.playNext(), delay);
}, delay);
}
}
// Usage for cutscenes or tutorials
const introSequence = new SoundSequence();
introSequence.addSound(new Sound("voices/intro1.wav"), 1000);
introSequence.addSound(new Sound("voices/intro2.wav"), 2000);
introSequence.addSound(new Sound("voices/intro3.wav"), 1500);
introSequence.play();
🎚️ Advanced Audio Techniques
Spatial Audio Simulation
class SpatialAudio {
constructor(sound, maxDistance = 500) {
this.sound = sound;
this.maxDistance = maxDistance;
}
playAt(x, y, listenerX, listenerY) {
const distance = Math.sqrt((x - listenerX) ** 2 + (y - listenerY) ** 2);
const volume = Math.max(0, 1 - (distance / this.maxDistance));
this.sound.sound.volume = volume;
this.sound.play();
// Reset volume after playback starts
setTimeout(() => {
this.sound.sound.volume = 1.0;
}, 100);
}
}
// Usage
const explosionSpatial = new SpatialAudio(new Sound("sounds/explosion.wav"));
function playDistantExplosion(x, y) {
const playerX = player.x + player.width / 2;
const playerY = player.y + player.height / 2;
explosionSpatial.playAt(x, y, playerX, playerY);
}
Audio Fading Effects
class AudioFader {
constructor(sound) {
this.sound = sound;
this.fadeInterval = null;
}
fadeIn(duration = 2000) {
this.sound.sound.volume = 0;
this.sound.play();
const steps = duration / 50; // 50ms intervals
const volumeStep = 1 / steps;
let currentStep = 0;
this.fadeInterval = setInterval(() => {
currentStep++;
this.sound.sound.volume = Math.min(1, volumeStep * currentStep);
if (currentStep >= steps) {
clearInterval(this.fadeInterval);
}
}, 50);
}
fadeOut(duration = 2000) {
const steps = duration / 50;
const volumeStep = this.sound.sound.volume / steps;
let currentStep = 0;
this.fadeInterval = setInterval(() => {
currentStep++;
this.sound.sound.volume = Math.max(0, this.sound.sound.volume - volumeStep);
if (currentStep >= steps) {
this.sound.stop();
clearInterval(this.fadeInterval);
}
}, 50);
}
}
// Usage for smooth music transitions
const musicFader = new AudioFader(backgroundMusic);
musicFader.fadeIn(3000); // Fade in over 3 seconds
// Later when changing levels
musicFader.fadeOut(2000); // Fade out over 2 seconds
🎮 Complete Game Audio System
Comprehensive Audio Manager
class GameAudioManager {
constructor() {
this.sounds = new Map();
this.music = null;
this.masterVolume = 1.0;
this.sfxVolume = 0.8;
this.musicVolume = 0.6;
this.muted = false;
}
loadSound(name, path, options = {}) {
const sound = new Sound(path);
if (options.volume) {
sound.sound.volume = options.volume;
}
this.sounds.set(name, {
sound: sound,
type: options.type || 'sfx',
pool: options.pool ? new SoundPool(path, options.pool) : null
});
}
play(name) {
if (this.muted || !this.sounds.has(name)) return;
const soundData = this.sounds.get(name);
if (soundData.pool) {
soundData.pool.play();
} else {
soundData.sound.play();
}
}
playMusic(name) {
if (this.music) {
this.music.stop();
}
if (this.sounds.has(name)) {
this.music = this.sounds.get(name).sound;
this.music.play();
// Enable looping for music
this.music.sound.loop = true;
}
}
setVolume(type, volume) {
switch(type) {
case 'master':
this.masterVolume = volume;
break;
case 'sfx':
this.sfxVolume = volume;
break;
case 'music':
this.musicVolume = volume;
break;
}
this.updateAllVolumes();
}
updateAllVolumes() {
this.sounds.forEach((soundData, name) => {
let volume = this.masterVolume;
if (soundData.type === 'sfx') volume *= this.sfxVolume;
if (soundData.type === 'music') volume *= this.musicVolume;
soundData.sound.sound.volume = this.muted ? 0 : volume;
});
}
toggleMute() {
this.muted = !this.muted;
this.updateAllVolumes();
}
}
// Usage
const audioManager = new GameAudioManager();
// Load sounds
audioManager.loadSound('jump', 'sounds/jump.wav', { type: 'sfx', volume: 0.7 });
audioManager.loadSound('coin', 'sounds/coin.wav', { type: 'sfx', volume: 0.8 });
audioManager.loadSound('explosion', 'sounds/explosion.wav', { type: 'sfx', pool: 3 });
audioManager.loadSound('bg_music', 'music/theme.mp3', { type: 'music', volume: 0.5 });
// Play sounds in game
function update() {
if (display.keys[32] && player.gravitySpeed === 0) {
audioManager.play('jump');
}
}
// Start background music
audioManager.playMusic('bg_music');
⚡ Performance Optimization
Sound Preloading and Caching
class SoundPreloader {
constructor() {
this.loadedSounds = new Map();
this.loadingPromises = [];
}
preload(soundList) {
soundList.forEach(soundDef => {
const promise = new Promise((resolve) => {
const sound = new Sound(soundDef.path);
sound.sound.addEventListener('canplaythrough', () => {
this.loadedSounds.set(soundDef.name, sound);
resolve();
});
sound.sound.load(); // Force loading
});
this.loadingPromises.push(promise);
});
return Promise.all(this.loadingPromises);
}
getSound(name) {
return this.loadedSounds.get(name);
}
}
// Usage
const preloader = new SoundPreloader();
const soundsToPreload = [
{ name: 'jump', path: 'sounds/jump.wav' },
{ name: 'coin', path: 'sounds/coin.wav' },
{ name: 'bg_music', path: 'music/theme.mp3' }
];
preloader.preload(soundsToPreload).then(() => {
console.log('All sounds loaded!');
// Start game
});
🐛 Common Issues and Solutions
Audio Autoplay Restrictions
// Handle browser autoplay policies
function setupAudioWithUserInteraction() {
let audioEnabled = false;
// Enable audio on first user interaction
document.addEventListener('click', function enableAudio() {
if (!audioEnabled) {
audioEnabled = true;
backgroundMusic.play();
document.removeEventListener('click', enableAudio);
}
});
}
// Alternative: Audio context resume
async function unlockAudio() {
const context = new (window.AudioContext || window.webkitAudioContext)();
await context.resume();
// Now audio should play
backgroundMusic.play();
}
File Format Compatibility
// Support multiple formats for better compatibility
class MultiFormatSound {
constructor(basePath, formats = ['mp3', 'wav', 'ogg']) {
this.sound = null;
for (let format of formats) {
const testSound = new Sound(`${basePath}.${format}`);
// Check if format is supported
if (testSound.sound.canPlayType) {
this.sound = testSound;
break;
}
}
if (!this.sound) {
console.warn(`No supported audio format found for: ${basePath}`);
}
}
play() {
if (this.sound) this.sound.play();
}
stop() {
if (this.sound) this.sound.stop();
}
}
// Usage
const compatibleSound = new MultiFormatSound('sounds/jump', ['mp3', 'wav', 'ogg']);
📚 Conclusion
TCJSGame's Sound Class provides:
- Simple audio playback with minimal code
- HTML5 Audio API integration for broad compatibility
- Flexible sound management for various game types
- Basic volume control through direct property access
- Easy integration with game events and interactions
While the base Sound Class is simple, you can extend it with:
- Audio managers for volume control and organization
- Sound pools for frequent effects
- Spatial audio for immersive experiences
- Fading effects for smooth transitions
- Preloading systems for better performance
Sound is crucial for game immersion, and TCJSGame makes it accessible for developers of all skill levels. Combine these audio techniques with TCJSGame's visual and movement systems to create truly engaging gaming experiences!
Top comments (0)