update : cinematic trigger

This commit is contained in:
math-pixel
2026-05-12 17:07:53 +02:00
parent ae34dc38ed
commit ff79448ce8
5 changed files with 45 additions and 8 deletions
+15
View File
@@ -1,6 +1,21 @@
{
"version": 1,
"cinematics": [
{
"id": "intro_sequence",
"trigger": "intro_sequence",
"cameraKeyframes": [
{ "time": 0, "position": [8, 5, 12], "target": [0, 2, 0] },
{ "time": 8, "position": [12, 4, -6], "target": [10, 1.4, -8] },
{ "time": 16, "position": [5, 6, -15], "target": [0, 3, -20] },
{ "time": 24, "position": [0, 8, -30], "target": [0, 0, -40] }
],
"dialogueCues": [
{ "time": 0, "dialogueId": "intro_welcome" },
{ "time": 8, "dialogueId": "intro_explanation" },
{ "time": 16, "dialogueId": "intro_mission" }
]
},
{
"id": "intro_overview",
"timecode": 0,
+6 -8
View File
@@ -6,6 +6,7 @@ import { AUDIO_PATHS } from "@/data/audioConfig";
export function GameFlow(): null {
const step = useGameStore((state) => state.intro.currentStep);
const setStep = useGameStore((state) => state.setIntroStep);
const isCinematicPlaying = useGameStore((state) => state.isCinematicPlaying);
const setActivityCity = useGameStore((state) => state.setActivityCity);
const setCanMove = useGameStore((state) => state.setCanMove);
const hasInitialized = useRef(false);
@@ -13,20 +14,17 @@ export function GameFlow(): null {
useEffect(() => {
if (!hasInitialized.current && step === "intro") {
hasInitialized.current = true;
setStep("start-intro");
setStep("intro_sequence");
}
}, [step, setStep]);
useEffect(() => {
if (step === "start-intro") {
const audio = AudioManager.getInstance();
audio.playSoundWithCallback(AUDIO_PATHS.intro, 0.5, () => {
setStep("naming");
});
return () => {};
if (step === "intro_sequence" && !isCinematicPlaying) {
setStep("naming");
}
}, [step, isCinematicPlaying, setStep]);
useEffect(() => {
if (step === "bienvenue") {
const audio = AudioManager.getInstance();
audio.playSoundWithCallback(AUDIO_PATHS.bienvenue, 0.5, () => {
+1
View File
@@ -14,6 +14,7 @@ export interface CinematicDialogueCue {
export interface CinematicDefinition {
id: string;
timecode?: number;
trigger?: string;
cameraKeyframes: CinematicCameraKeyframe[];
dialogueCues?: CinematicDialogueCue[];
}
+2
View File
@@ -2,6 +2,7 @@ import type { Vector3Tuple } from "@/types/three/three";
export type GameStep =
| "intro"
| "intro_sequence"
| "start-intro"
| "naming"
| "bienvenue"
@@ -14,6 +15,7 @@ export type GameStep =
export const GAME_STEPS: readonly GameStep[] = [
"intro",
"intro_sequence",
"start-intro",
"naming",
"bienvenue",
+21
View File
@@ -20,6 +20,7 @@ export function GameCinematics(): null {
const [dialogueManifest, setDialogueManifest] =
useState<DialogueManifest | null>(null);
const playedCinematicsRef = useRef(new Set<string>());
const triggeredCinematicsRef = useRef(new Set<string>());
const timelineRef = useRef<gsap.core.Timeline | null>(null);
const activeAudiosRef = useRef(new Set<HTMLAudioElement>());
const startedAtRef = useRef<number | null>(null);
@@ -64,7 +65,25 @@ export function GameCinematics(): null {
const elapsedTime = clock.getElapsedTime() - startedAtRef.current;
const currentStep = useGameStore.getState().intro.currentStep;
manifest.cinematics.forEach((cinematic) => {
if (cinematic.trigger) {
if (triggeredCinematicsRef.current.has(cinematic.id)) return;
if (currentStep !== cinematic.trigger) return;
if (cinematic.dialogueCues && !dialogueManifest) return;
triggeredCinematicsRef.current.add(cinematic.id);
playCinematic(camera, cinematic, timelineRef, {
dialogueManifest,
activeAudiosRef,
onComplete: () => {
triggeredCinematicsRef.current.delete(cinematic.id);
},
});
return;
}
if (cinematic.timecode === undefined) return;
if (cinematic.timecode > elapsedTime) return;
if (cinematic.dialogueCues && !dialogueManifest) return;
@@ -95,6 +114,7 @@ function playCinematic(
dialogueOptions: {
dialogueManifest: DialogueManifest | null;
activeAudiosRef: MutableRefObject<Set<HTMLAudioElement>>;
onComplete?: () => void;
},
): void {
const firstKeyframe = cinematic.cameraKeyframes[0];
@@ -113,6 +133,7 @@ function playCinematic(
onComplete: () => {
timelineRef.current = null;
useGameStore.getState().setCinematicPlaying(false);
dialogueOptions.onComplete?.();
},
});