add: trigger dialogue with timecode

This commit is contained in:
Tom Boullay
2026-05-10 00:10:16 +01:00
parent 53fdf3cb1e
commit 0fbf6bfa0e
2 changed files with 61 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
import { useEffect, useRef, useState } from "react";
import { useFrame } from "@react-three/fiber";
import type { DialogueManifest } from "@/types/dialogues/dialogues";
import { loadDialogueManifest } from "@/utils/dialogues/loadDialogueManifest";
import { playDialogueById } from "@/utils/dialogues/playDialogue";
import { logger } from "@/utils/core/logger";
export function GameDialogues(): null {
const [manifest, setManifest] = useState<DialogueManifest | null>(null);
const playedDialoguesRef = useRef(new Set<string>());
const activeAudiosRef = useRef(new Set<HTMLAudioElement>());
useEffect(() => {
let mounted = true;
const activeAudios = activeAudiosRef.current;
void loadDialogueManifest()
.then((loadedManifest) => {
if (mounted) setManifest(loadedManifest);
})
.catch((error: unknown) => {
logger.error("GameDialogues", "Failed to load dialogue manifest", {
error: error instanceof Error ? error : String(error),
});
});
return () => {
mounted = false;
activeAudios.forEach((audio) => audio.pause());
activeAudios.clear();
};
}, []);
useFrame(({ clock }) => {
if (!manifest) return;
const elapsedTime = clock.getElapsedTime();
manifest.dialogues.forEach((dialogue) => {
if (dialogue.timecode === undefined) return;
if (dialogue.timecode > elapsedTime) return;
if (playedDialoguesRef.current.has(dialogue.id)) return;
playedDialoguesRef.current.add(dialogue.id);
void playDialogueById(manifest, dialogue.id).then((audio) => {
if (!audio) return;
activeAudiosRef.current.add(audio);
audio.addEventListener(
"ended",
() => activeAudiosRef.current.delete(audio),
{ once: true },
);
});
});
});
return null;
}
+2
View File
@@ -10,6 +10,7 @@ import { DebugCameraControls } from "@/components/debug/scene/DebugCameraControl
import { DebugHelpers } from "@/components/debug/scene/DebugHelpers"; import { DebugHelpers } from "@/components/debug/scene/DebugHelpers";
import { HandTrackingGlove } from "@/components/three/handTracking/HandTrackingGlove"; import { HandTrackingGlove } from "@/components/three/handTracking/HandTrackingGlove";
import { Environment } from "@/world/Environment"; import { Environment } from "@/world/Environment";
import { GameDialogues } from "@/world/GameDialogues";
import { GameMusic } from "@/world/GameMusic"; import { GameMusic } from "@/world/GameMusic";
import { Lighting } from "@/world/Lighting"; import { Lighting } from "@/world/Lighting";
import { GameMap } from "@/world/GameMap"; import { GameMap } from "@/world/GameMap";
@@ -42,6 +43,7 @@ export function World(): React.JSX.Element {
{sceneMode === "game" ? ( {sceneMode === "game" ? (
<> <>
<GameMusic /> <GameMusic />
<GameDialogues />
<GameMap onOctreeReady={setOctree} /> <GameMap onOctreeReady={setOctree} />
<GameStageContent /> <GameStageContent />
</> </>