Ajoute un son de fusion dans La Corne d'Abondance
Build and deploy / deploy (push) Successful in 36s
Build and deploy / deploy (push) Successful in 36s
Pas de fichier audio dans le projet, donc un petit "pop" synthétisé via Web Audio (src/lib/melon/sound.ts), joué à chaque fusion. La hauteur baisse avec le palier de la pièce obtenue, pour que fusionner deux grosses pièces sonne différemment de deux petites. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
MAX_FRAME_DT_MS,
|
MAX_FRAME_DT_MS,
|
||||||
WALL_THICKNESS,
|
WALL_THICKNESS,
|
||||||
} from "@/lib/melon/constants";
|
} from "@/lib/melon/constants";
|
||||||
|
import { playMergeSound } from "@/lib/melon/sound";
|
||||||
import type { MemberRow } from "./page";
|
import type { MemberRow } from "./page";
|
||||||
|
|
||||||
type Status = "playing" | "dead";
|
type Status = "playing" | "dead";
|
||||||
@@ -329,10 +330,12 @@ export function MelonGame({
|
|||||||
const newTier = merge.tier + 1;
|
const newTier = merge.tier + 1;
|
||||||
scoreRef.current += newTier;
|
scoreRef.current += newTier;
|
||||||
spawned.push(spawnPiece(newTier, merge.x, merge.y));
|
spawned.push(spawnPiece(newTier, merge.x, merge.y));
|
||||||
|
playMergeSound(newTier, maxTier);
|
||||||
} else {
|
} else {
|
||||||
// Palier maximum déjà atteint : pas de pièce plus grande, juste
|
// Palier maximum déjà atteint : pas de pièce plus grande, juste
|
||||||
// un bonus de score pour la fusion finale.
|
// un bonus de score pour la fusion finale.
|
||||||
scoreRef.current += maxTier * 2;
|
scoreRef.current += maxTier * 2;
|
||||||
|
playMergeSound(maxTier, maxTier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Petit "pop" synthétisé via Web Audio (pas de fichier audio dans le
|
||||||
|
// projet, cohérent avec le reste de l'app qui dessine tout plutôt que de
|
||||||
|
// dépendre d'assets externes — voir les ornements SVG/canvas ailleurs).
|
||||||
|
// AudioContext créé paresseusement au premier appel : le construire avant
|
||||||
|
// une interaction utilisateur déclenche des avertissements navigateur
|
||||||
|
// (autoplay policy) — ici le premier merge n'arrive jamais avant un
|
||||||
|
// premier lâcher, donc toujours après un vrai geste utilisateur.
|
||||||
|
let audioContext: AudioContext | null = null;
|
||||||
|
|
||||||
|
function getAudioContext(): AudioContext | null {
|
||||||
|
if (typeof window === "undefined") return null;
|
||||||
|
if (!audioContext) {
|
||||||
|
const Ctor =
|
||||||
|
window.AudioContext ??
|
||||||
|
(window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;
|
||||||
|
if (!Ctor) return null;
|
||||||
|
audioContext = new Ctor();
|
||||||
|
}
|
||||||
|
if (audioContext.state === "suspended") {
|
||||||
|
audioContext.resume().catch(() => {});
|
||||||
|
}
|
||||||
|
return audioContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fréquence plus grave à mesure que le palier de la pièce issue de la
|
||||||
|
// fusion monte : deux petites pièces qui fusionnent ne doit pas "sonner"
|
||||||
|
// comme deux grosses.
|
||||||
|
export function playMergeSound(tier: number, maxTier: number): void {
|
||||||
|
const ctx = getAudioContext();
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const progress = maxTier > 0 ? Math.min(1, Math.max(0, tier / maxTier)) : 0;
|
||||||
|
const baseFreq = 720 - progress * 380;
|
||||||
|
const now = ctx.currentTime;
|
||||||
|
|
||||||
|
const oscillator = ctx.createOscillator();
|
||||||
|
const gain = ctx.createGain();
|
||||||
|
oscillator.type = "sine";
|
||||||
|
oscillator.frequency.setValueAtTime(baseFreq, now);
|
||||||
|
oscillator.frequency.exponentialRampToValueAtTime(baseFreq * 1.6, now + 0.08);
|
||||||
|
|
||||||
|
gain.gain.setValueAtTime(0.0001, now);
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.25, now + 0.01);
|
||||||
|
gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.18);
|
||||||
|
|
||||||
|
oscillator.connect(gain);
|
||||||
|
gain.connect(ctx.destination);
|
||||||
|
oscillator.start(now);
|
||||||
|
oscillator.stop(now + 0.2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user