feat: video player
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useGameStore } from "@/managers/stores/useGameStore";
|
||||
|
||||
export function VideoPlayer(): null {
|
||||
const currentVideo = useGameStore((state) => state.missionFlow.currentVideo);
|
||||
const clearVideo = useGameStore((state) => state.clearVideo);
|
||||
const setCinematicPlaying = useGameStore(
|
||||
(state) => state.setCinematicPlaying,
|
||||
);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentVideo) {
|
||||
setCinematicPlaying(true);
|
||||
}
|
||||
}, [currentVideo, setCinematicPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape" && currentVideo) {
|
||||
closeVideo();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [currentVideo]);
|
||||
|
||||
const closeVideo = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.pause();
|
||||
}
|
||||
clearVideo();
|
||||
setCinematicPlaying(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
|
||||
const handleEnded = () => {
|
||||
closeVideo();
|
||||
};
|
||||
|
||||
video.addEventListener("ended", handleEnded);
|
||||
return () => video.removeEventListener("ended", handleEnded);
|
||||
}, []);
|
||||
|
||||
if (!currentVideo) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.95)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 9999,
|
||||
}}
|
||||
>
|
||||
<video
|
||||
ref={videoRef}
|
||||
src={currentVideo}
|
||||
autoPlay
|
||||
playsInline
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={closeVideo}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -29,6 +29,7 @@ interface MissionFlowState {
|
||||
canMove: boolean;
|
||||
dialogMessage: string | null;
|
||||
playerName: string;
|
||||
currentVideo: string | null;
|
||||
}
|
||||
|
||||
interface GameState {
|
||||
@@ -78,6 +79,8 @@ interface GameActions {
|
||||
rewindGameState: () => void;
|
||||
resetGame: () => void;
|
||||
showDialog: (dialogMessage: string) => void;
|
||||
playVideo: (videoSrc: string) => void;
|
||||
clearVideo: () => void;
|
||||
}
|
||||
|
||||
type GameStore = GameState & GameActions;
|
||||
@@ -233,6 +236,7 @@ function createInitialGameState(): GameState {
|
||||
canMove: false,
|
||||
dialogMessage: null,
|
||||
playerName: "",
|
||||
currentVideo: null,
|
||||
},
|
||||
intro: {
|
||||
currentStep: "intro",
|
||||
@@ -342,4 +346,12 @@ export const useGameStore = create<GameStore>()((set) => ({
|
||||
set((state) => ({
|
||||
missionFlow: { ...state.missionFlow, dialogMessage },
|
||||
})),
|
||||
playVideo: (videoSrc) =>
|
||||
set((state) => ({
|
||||
missionFlow: { ...state.missionFlow, currentVideo: videoSrc },
|
||||
})),
|
||||
clearVideo: () =>
|
||||
set((state) => ({
|
||||
missionFlow: { ...state.missionFlow, currentVideo: null },
|
||||
})),
|
||||
}));
|
||||
|
||||
@@ -29,6 +29,7 @@ import { GameStageContent } from "@/world/GameStageContent";
|
||||
import { Player } from "@/world/player/Player";
|
||||
import { TestMap } from "@/world/debug/TestMap";
|
||||
import { NetTest } from "@/components/three/NetTest";
|
||||
import { VideoPlayer } from "@/components/ui/VideoPlayer";
|
||||
import type { SceneLoadingChangeHandler } from "@/types/world/sceneLoading";
|
||||
|
||||
interface WorldProps {
|
||||
@@ -62,6 +63,7 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<Environment />
|
||||
<VideoPlayer />
|
||||
<Lighting />
|
||||
<DebugHelpers />
|
||||
{showHandTrackingGloves ? (
|
||||
|
||||
Reference in New Issue
Block a user