Files
WebFactory/js/audio.js
2026-01-13 18:32:05 +00:00

189 lines
5.8 KiB
JavaScript

// Audio System
const Audio = {
ctx: null,
enabled: true,
volume: 0.3,
// Initialize audio context
init() {
// Create on first user interaction
document.addEventListener('click', () => this.ensureContext(), { once: true });
document.addEventListener('keydown', () => this.ensureContext(), { once: true });
},
ensureContext() {
if (!this.ctx) {
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
}
},
// Play a tone
playTone(frequency, duration, type = 'square', volume = null) {
if (!this.enabled || !this.ctx) return;
try {
const oscillator = this.ctx.createOscillator();
const gainNode = this.ctx.createGain();
oscillator.connect(gainNode);
gainNode.connect(this.ctx.destination);
oscillator.frequency.value = frequency;
oscillator.type = type;
const vol = (volume || this.volume) * this.volume;
gainNode.gain.setValueAtTime(vol, this.ctx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration);
oscillator.start(this.ctx.currentTime);
oscillator.stop(this.ctx.currentTime + duration);
} catch (e) {
// Ignore audio errors
}
},
// Play noise burst (for explosions, etc)
playNoise(duration, volume = null) {
if (!this.enabled || !this.ctx) return;
try {
const bufferSize = this.ctx.sampleRate * duration;
const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = Math.random() * 2 - 1;
}
const noise = this.ctx.createBufferSource();
const gainNode = this.ctx.createGain();
const filter = this.ctx.createBiquadFilter();
noise.buffer = buffer;
filter.type = 'lowpass';
filter.frequency.value = 1000;
noise.connect(filter);
filter.connect(gainNode);
gainNode.connect(this.ctx.destination);
const vol = (volume || this.volume) * this.volume;
gainNode.gain.setValueAtTime(vol, this.ctx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration);
noise.start(this.ctx.currentTime);
} catch (e) {
// Ignore audio errors
}
},
// Sound effects
playPlace() {
this.playTone(200, 0.1, 'square', 0.2);
setTimeout(() => this.playTone(300, 0.08, 'square', 0.15), 50);
},
playDelete() {
this.playTone(150, 0.15, 'sawtooth', 0.2);
setTimeout(() => this.playTone(100, 0.1, 'sawtooth', 0.15), 80);
},
playMine() {
this.playTone(100 + Math.random() * 50, 0.08, 'triangle', 0.15);
},
playMineComplete() {
this.playTone(400, 0.1, 'sine', 0.2);
setTimeout(() => this.playTone(500, 0.08, 'sine', 0.15), 60);
},
playShoot(towerType) {
switch(towerType) {
case 'gun_turret':
this.playNoise(0.05, 0.3);
this.playTone(150, 0.05, 'square', 0.2);
break;
case 'flame_turret':
this.playNoise(0.15, 0.25);
this.playTone(80, 0.1, 'sawtooth', 0.15);
break;
case 'laser_turret':
this.playTone(800, 0.15, 'sine', 0.25);
this.playTone(1200, 0.1, 'sine', 0.15);
break;
case 'tesla_turret':
this.playTone(200, 0.05, 'sawtooth', 0.2);
this.playTone(400, 0.1, 'sawtooth', 0.15);
this.playTone(300, 0.08, 'sawtooth', 0.1);
break;
case 'cannon_turret':
this.playNoise(0.2, 0.4);
this.playTone(60, 0.2, 'triangle', 0.3);
break;
default:
this.playTone(200, 0.05, 'square', 0.2);
}
},
playExplosion() {
this.playNoise(0.3, 0.4);
this.playTone(50, 0.3, 'triangle', 0.3);
setTimeout(() => this.playTone(40, 0.2, 'triangle', 0.2), 100);
},
playEnemyHit() {
this.playTone(150, 0.05, 'square', 0.1);
},
playEnemyDeath() {
this.playTone(200, 0.1, 'sawtooth', 0.2);
setTimeout(() => this.playTone(100, 0.15, 'sawtooth', 0.15), 50);
},
playWaveStart() {
const notes = [300, 400, 300, 500];
notes.forEach((freq, i) => {
setTimeout(() => this.playTone(freq, 0.2, 'square', 0.25), i * 150);
});
},
playWaveComplete() {
const notes = [400, 500, 600, 800];
notes.forEach((freq, i) => {
setTimeout(() => this.playTone(freq, 0.15, 'sine', 0.25), i * 100);
});
},
playBuildingDamage() {
this.playTone(100, 0.1, 'sawtooth', 0.2);
},
playBuildingDestroyed() {
this.playNoise(0.3, 0.35);
this.playTone(80, 0.3, 'sawtooth', 0.25);
},
playUIClick() {
this.playTone(400, 0.05, 'sine', 0.1);
},
playError() {
this.playTone(150, 0.15, 'square', 0.2);
setTimeout(() => this.playTone(100, 0.15, 'square', 0.15), 100);
},
playDevMode() {
this.playTone(600, 0.1, 'sine', 0.2);
setTimeout(() => this.playTone(800, 0.1, 'sine', 0.2), 100);
},
// Toggle sound
toggle() {
this.enabled = !this.enabled;
if (this.enabled) {
this.playUIClick();
}
return this.enabled;
}
};