feat(effects): extinguish fire with water/rain and ambient SFX volume
Water and rain erase fire under a tight brush hit radius; add looping fire/rain ambients and an Effects sound slider that also scales one-shot effect SFX. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
/** Фоновый звук дождя при наличии дождя на сцене (`public/rain-ambient.mp3`). */
|
||||
|
||||
import { getEffectsSfxGain } from './effectsSfxGain';
|
||||
|
||||
const RAIN_AMBIENT_BASE_VOLUME = 0.7;
|
||||
|
||||
export function rainAmbientSoundUrl(): string {
|
||||
return new URL('rain-ambient.mp3', window.location.href).href;
|
||||
}
|
||||
|
||||
let ambientEl: HTMLAudioElement | null = null;
|
||||
|
||||
function ensureAmbientEl(): HTMLAudioElement {
|
||||
if (ambientEl) return ambientEl;
|
||||
const el = new Audio(rainAmbientSoundUrl());
|
||||
el.loop = true;
|
||||
el.preload = 'auto';
|
||||
ambientEl = el;
|
||||
return el;
|
||||
}
|
||||
|
||||
function applyVolume(el: HTMLAudioElement): void {
|
||||
el.volume = Math.max(0, Math.min(1, RAIN_AMBIENT_BASE_VOLUME * getEffectsSfxGain()));
|
||||
}
|
||||
|
||||
/** Включить/выключить loop дождя. */
|
||||
export function setRainAmbientActive(active: boolean): void {
|
||||
try {
|
||||
const el = ensureAmbientEl();
|
||||
applyVolume(el);
|
||||
if (active) {
|
||||
if (el.paused) void el.play().catch(() => undefined);
|
||||
} else if (!el.paused) {
|
||||
el.pause();
|
||||
el.currentTime = 0;
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
/** Обновить громкость, если ambient уже играет. */
|
||||
export function syncRainAmbientVolume(): void {
|
||||
if (!ambientEl) return;
|
||||
try {
|
||||
applyVolume(ambientEl);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user