Feat/env-manager #1
@@ -3,6 +3,12 @@ import { logger } from "@/utils/core/logger";
|
||||
export type AudioCategory = "music" | "sfx" | "dialogue";
|
||||
export type OneShotAudioCategory = Exclude<AudioCategory, "music">;
|
||||
|
||||
const DEFAULT_CATEGORY_VOLUMES: Record<AudioCategory, number> = {
|
||||
music: 1,
|
||||
sfx: 1,
|
||||
dialogue: 1,
|
||||
};
|
||||
|
||||
interface PlaySoundOptions {
|
||||
category?: OneShotAudioCategory;
|
||||
playbackRate?: number;
|
||||
@@ -11,8 +17,12 @@ interface PlaySoundOptions {
|
||||
export class AudioManager {
|
||||
private static _instance: AudioManager | null = null;
|
||||
private readonly _audioPools = new Map<string, HTMLAudioElement[]>();
|
||||
private readonly _categoryVolumes: Record<AudioCategory, number> = {
|
||||
...DEFAULT_CATEGORY_VOLUMES,
|
||||
};
|
||||
private _music: HTMLAudioElement | null = null;
|
||||
private _musicPath: string | null = null;
|
||||
private _musicVolume = 1;
|
||||
private _musicUnlockHandler: (() => void) | null = null;
|
||||
|
||||
private static readonly MAX_POOL_SIZE_PER_SOUND = 6;
|
||||
@@ -32,10 +42,22 @@ export class AudioManager {
|
||||
|
||||
private constructor() {}
|
||||
|
||||
setCategoryVolume(category: AudioCategory, volume: number): void {
|
||||
this._categoryVolumes[category] = AudioManager._clampVolume(volume);
|
||||
|
||||
if (category === "music" && this._music) {
|
||||
this._music.volume = this._getEffectiveVolume("music", this._musicVolume);
|
||||
}
|
||||
}
|
||||
|
||||
getCategoryVolume(category: AudioCategory): number {
|
||||
return this._categoryVolumes[category];
|
||||
}
|
||||
|
||||
playSound(path: string, volume = 1, options: PlaySoundOptions = {}): void {
|
||||
const audio = this._acquireAudio(path);
|
||||
const category = options.category ?? AudioManager.DEFAULT_SOUND_CATEGORY;
|
||||
audio.volume = Math.max(0, Math.min(1, volume));
|
||||
audio.volume = this._getEffectiveVolume(category, volume);
|
||||
audio.playbackRate = options.playbackRate ?? 1;
|
||||
audio.currentTime = 0;
|
||||
|
||||
@@ -56,8 +78,10 @@ export class AudioManager {
|
||||
}
|
||||
|
||||
playMusic(path: string, volume = 1): void {
|
||||
this._musicVolume = AudioManager._clampVolume(volume);
|
||||
|
||||
if (this._musicPath === path && this._music) {
|
||||
this._music.volume = Math.max(0, Math.min(1, volume));
|
||||
this._music.volume = this._getEffectiveVolume("music", this._musicVolume);
|
||||
if (!this._music.paused) return;
|
||||
} else {
|
||||
this.stopMusic();
|
||||
@@ -66,7 +90,7 @@ export class AudioManager {
|
||||
this._musicPath = path;
|
||||
}
|
||||
|
||||
this._music.volume = Math.max(0, Math.min(1, volume));
|
||||
this._music.volume = this._getEffectiveVolume("music", this._musicVolume);
|
||||
|
||||
void this._music.play().catch((error: unknown) => {
|
||||
if (
|
||||
@@ -151,6 +175,14 @@ export class AudioManager {
|
||||
this._musicUnlockHandler = null;
|
||||
}
|
||||
|
||||
private _getEffectiveVolume(category: AudioCategory, volume: number): number {
|
||||
return AudioManager._clampVolume(volume) * this._categoryVolumes[category];
|
||||
}
|
||||
|
||||
private static _clampVolume(volume: number): number {
|
||||
return Math.max(0, Math.min(1, volume));
|
||||
}
|
||||
|
||||
private static _toLogValue(error: unknown): Error | DOMException | string {
|
||||
if (error instanceof Error || error instanceof DOMException) {
|
||||
return error;
|
||||
|
||||
Reference in New Issue
Block a user