62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)();
|
|
|
|
const sounds: Record<string, AudioBuffer> = {};
|
|
|
|
async function loadSound(name: string): Promise<AudioBuffer> {
|
|
const response = await fetch(`./sounds/${name}.ogg`);
|
|
const arrayBuffer = await response.arrayBuffer();
|
|
return audioCtx.decodeAudioData(arrayBuffer);
|
|
}
|
|
|
|
export async function initSounds() {
|
|
const names = ['fireball', 'explosion', 'sword_hit1', 'teleport', 'damage', 'spiderwalking', 'spawn', 'gameover'];
|
|
for (const name of names) {
|
|
try {
|
|
sounds[name] = await loadSound(name);
|
|
} catch {
|
|
console.warn(`Sound ${name} not found`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function resumeContext() {
|
|
if (audioCtx.state === 'suspended') {
|
|
audioCtx.resume();
|
|
}
|
|
}
|
|
|
|
export function playSound(name: string, volume = 1) {
|
|
const buffer = sounds[name];
|
|
if (!buffer) return;
|
|
if (audioCtx.state === 'suspended') return;
|
|
const source = audioCtx.createBufferSource();
|
|
source.buffer = buffer;
|
|
const gain = audioCtx.createGain();
|
|
gain.gain.value = volume;
|
|
source.connect(gain);
|
|
gain.connect(audioCtx.destination);
|
|
source.start(0);
|
|
}
|
|
|
|
export function playLoopingSound(name: string, volume = 1): (() => void) | null {
|
|
const buffer = sounds[name];
|
|
if (!buffer) return null;
|
|
if (audioCtx.state === 'suspended') return null;
|
|
const source = audioCtx.createBufferSource();
|
|
source.buffer = buffer;
|
|
source.loop = true;
|
|
const gain = audioCtx.createGain();
|
|
gain.gain.value = volume;
|
|
source.connect(gain);
|
|
gain.connect(audioCtx.destination);
|
|
source.start(0);
|
|
return () => {
|
|
try {
|
|
source.stop();
|
|
} catch {
|
|
// already stopped
|
|
}
|
|
source.disconnect();
|
|
};
|
|
}
|