update : cinematic trigger
This commit is contained in:
@@ -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,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, () => {
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface CinematicDialogueCue {
|
||||
export interface CinematicDefinition {
|
||||
id: string;
|
||||
timecode?: number;
|
||||
trigger?: string;
|
||||
cameraKeyframes: CinematicCameraKeyframe[];
|
||||
dialogueCues?: CinematicDialogueCue[];
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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?.();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user