diff --git a/public/sprite/gate_object_texture.png b/public/sprite/gate_object_texture.png deleted file mode 100644 index 16cb7f5..0000000 Binary files a/public/sprite/gate_object_texture.png and /dev/null differ diff --git a/src/components/Boot/BootAnimation.tsx b/src/components/Boot/BootAnimation.tsx index 0fe5d68..5c222d8 100644 --- a/src/components/Boot/BootAnimation.tsx +++ b/src/components/Boot/BootAnimation.tsx @@ -14,10 +14,10 @@ import bootBackgroundDistortedTex from "../../static/sprite/distorted_text.png"; import { useFrame, useLoader } from "react-three-fiber"; import { a, useSpring } from "@react-spring/three"; import * as THREE from "three"; -import { OrbitControls } from "@react-three/drei"; type BootAnimationProps = { visible: boolean; + activeSubScene: string; }; const BootAnimation = (props: BootAnimationProps) => { @@ -149,7 +149,8 @@ const BootAnimation = (props: BootAnimationProps) => { setLofPosY(1); setBackgroundFloatingTextShown(true); - }, 4200); + //4200 + }, 0); } }, [bootBackgroundTextTex, currentBootStatusTextTex.offset, props.visible]); @@ -163,11 +164,12 @@ const BootAnimation = (props: BootAnimationProps) => { config: { duration: 300 }, }); - const positionState = useSpring({ + const animationState = useSpring({ graySquarePosY: graySquarePosY, lofPosX: lofPosX, lofPosY: lofPosY, - config: { duration: 600 }, + lofOpacity: props.activeSubScene === "main_menu" ? 1 : 0, + config: { duration: 500 }, }); const firstBackgroundTextRef = useRef(); @@ -177,7 +179,18 @@ const BootAnimation = (props: BootAnimationProps) => { return ( <> - {props.visible ? ( + + + + {props.visible && props.activeSubScene === "main_menu" ? ( <> {/*we have two of each to create looping effect*/} { /> - - - - { { + const authorizeHeaderUnderlineTex = useLoader( + THREE.TextureLoader, + authorizeHeaderUnderline + ); + const authorizeGlassTex = useLoader(THREE.TextureLoader, authorizeGlass); + const authorizeGlassUnderlineTex = useLoader( + THREE.TextureLoader, + authorizeGlassUnderline + ); + const authorizeOrangeSquareTex = useLoader( + THREE.TextureLoader, + authorizeOrangeSquare + ); + const authorizeStartToFinishTex = useLoader( + THREE.TextureLoader, + authorizeStartToFinish + ); + const authorizeInactiveLettersTex = useLoader( + THREE.TextureLoader, + authorizeInactiveLetters + ); + + return ( + <> + {props.visible ? ( + <> + + + + + + + + + + + + + + + + + + + + + + + + ) : ( + <> + )} + + ); +}; + +export default BootAuthorizeUser; diff --git a/src/components/Boot/BootMainMenu.tsx b/src/components/Boot/BootMainMenu.tsx deleted file mode 100644 index 086445b..0000000 --- a/src/components/Boot/BootMainMenu.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React from "react"; -import { a } from "@react-spring/three"; -import authorizeActive from "../../static/sprite/authorize_user_active.png"; -import authorizeInactive from "../../static/sprite/authorize_user_inactive.png"; -import loadDataActive from "../../static/sprite/load_data_active.png"; -import loadDataInactive from "../../static/sprite/load_data_inactive.png"; -import { useLoader } from "react-three-fiber"; -import * as THREE from "three"; -import { useMainMenuStore } from "../../store"; - -type BootMainMenuProps = { - visible: boolean; -}; - -const BootMainMenu = (props: BootMainMenuProps) => { - const activeMainMenuElement = useMainMenuStore( - (state) => state.activeMainMenuElement - ); - - const authorizeActiveTex = useLoader(THREE.TextureLoader, authorizeActive); - const authorizeInactiveTex = useLoader( - THREE.TextureLoader, - authorizeInactive - ); - const loadDataActiveTex = useLoader(THREE.TextureLoader, loadDataActive); - const loadDataInactiveTex = useLoader(THREE.TextureLoader, loadDataInactive); - - return ( - <> - {props.visible ? ( - <> - - - - - - - - - ) : ( - <> - )} - - ); -}; - -export default BootMainMenu; diff --git a/src/components/Boot/BootMainMenuComponents.tsx b/src/components/Boot/BootMainMenuComponents.tsx new file mode 100644 index 0000000..1d91989 --- /dev/null +++ b/src/components/Boot/BootMainMenuComponents.tsx @@ -0,0 +1,106 @@ +import React, { useMemo } from "react"; +import { a, useSpring } from "@react-spring/three"; +import authorizeActive from "../../static/sprite/authorize_user_active.png"; +import authorizeInactive from "../../static/sprite/authorize_user_inactive.png"; +import loadDataActive from "../../static/sprite/load_data_active.png"; +import loadDataInactive from "../../static/sprite/load_data_inactive.png"; +import { useLoader } from "react-three-fiber"; +import * as THREE from "three"; +import { useBootMainMenuStore } from "../../store"; +import authorizeUserHeader from "../../static/sprite/authorize_user_scene_header.png"; + +type BootMainMenuProps = { + visible: boolean; + activeSubScene: string; +}; + +const BootMainMenuComponents = (props: BootMainMenuProps) => { + const activeMainMenuElement = useBootMainMenuStore( + (state) => state.activeMainMenuElement + ); + const authorizeUserPos = useBootMainMenuStore( + (state) => state.authorizeUserPos + ); + + const authorizeActiveTex = useLoader(THREE.TextureLoader, authorizeActive); + const authorizeInactiveTex = useLoader( + THREE.TextureLoader, + authorizeInactive + ); + const authorizeUserHeaderTex = useLoader( + THREE.TextureLoader, + authorizeUserHeader + ); + + const loadDataActiveTex = useLoader(THREE.TextureLoader, loadDataActive); + const loadDataInactiveTex = useLoader(THREE.TextureLoader, loadDataInactive); + + const mainMenuAnimationState = useSpring({ + authorizeUserPosX: authorizeUserPos.x, + authorizeUserPosY: authorizeUserPos.y, + loadDataOpacity: props.activeSubScene === "main_menu" ? 1 : 0, + config: { duration: 500 }, + }); + + const authorizeUserTextState = useMemo(() => { + if (props.activeSubScene === "authorize_user") { + return { scale: [1.8, 0.16, 0], texture: authorizeUserHeaderTex }; + } else { + return { + scale: [1.8, 0.3, 0], + texture: + activeMainMenuElement === "authorize_user" + ? authorizeActiveTex + : authorizeInactiveTex, + }; + } + }, [ + activeMainMenuElement, + authorizeActiveTex, + authorizeInactiveTex, + authorizeUserHeaderTex, + props.activeSubScene, + ]); + + return ( + <> + {props.visible ? ( + <> + + + + + + + + + ) : ( + <> + )} + + ); +}; + +export default BootMainMenuComponents; diff --git a/src/core/StateManagers/EventManager.tsx b/src/core/StateManagers/EventManager.tsx index 069ca8a..4b50cf7 100644 --- a/src/core/StateManagers/EventManager.tsx +++ b/src/core/StateManagers/EventManager.tsx @@ -6,6 +6,7 @@ import BlueOrbManager from "./BlueOrbManager"; import BlueOrbHUDManager from "./BlueOrbHUDManager"; import { useBlueOrbStore, + useBootMainMenuStore, useLevelStore, useMediaStore, useSceneStore, @@ -19,9 +20,9 @@ import SceneManager from "./SceneManager"; import YellowTextManager from "./YellowTextManager"; import MediaImageManager from "./MediaImageManager"; import computeAction from "../computeAction"; -import available_blue_orbs_on_projection from "../../resources/available_blue_orbs_on_projection.json"; import LevelManager from "./LevelManager"; import MainMenuManager from "./MainMenuManager"; +import SubSceneManager from "./SubSceneManager"; const getKeyCodeAssociation = (keyCode: number): string => { const keyCodeAssocs = { @@ -53,6 +54,7 @@ export type GameContext = { currentLevel: string; siteRotIdx: string; activeMediaComponent: string; + activeMainMenuElement: string; }; const EventManager = () => { @@ -70,6 +72,11 @@ const EventManager = () => { (state) => state.activeMediaComponent ); + // boot scene + const activeMainMenuElement = useBootMainMenuStore( + (state) => state.activeMainMenuElement + ); + const [eventState, setEventState] = useState(); const [inputCooldown, setInputCooldown] = useState(false); @@ -81,8 +88,10 @@ const EventManager = () => { blueOrbMatrixIndices: blueOrbMatrixIndices, currentLevel: currentLevel, activeMediaComponent: activeMediaComponent, + activeMainMenuElement: activeMainMenuElement, }), [ + activeMainMenuElement, activeMediaComponent, blueOrbMatrixIndices, currentLevel, @@ -130,6 +139,7 @@ const EventManager = () => { + ); }; diff --git a/src/core/StateManagers/MainMenuManager.tsx b/src/core/StateManagers/MainMenuManager.tsx index d68511a..2ed13df 100644 --- a/src/core/StateManagers/MainMenuManager.tsx +++ b/src/core/StateManagers/MainMenuManager.tsx @@ -1,11 +1,14 @@ import { useCallback, useEffect } from "react"; import { StateManagerProps } from "./EventManager"; -import { useMainMenuStore } from "../../store"; +import { useBootMainMenuStore } from "../../store"; const MainMenuManager = (props: StateManagerProps) => { - const setActiveMainMenuElement = useMainMenuStore( + const setActiveMainMenuElement = useBootMainMenuStore( (state) => state.setActiveMainMenuElement ); + const setAuthorizeUserPos = useBootMainMenuStore( + (state) => state.setAuthorizeUserPos + ); const dispatchObject = useCallback( (event: string) => { @@ -18,11 +21,15 @@ const MainMenuManager = (props: StateManagerProps) => { action: setActiveMainMenuElement, value: "authorize_user", }, + select_authorize_user: { + action: setAuthorizeUserPos, + value: { x: 1.13, y: 1.2 }, + }, }; return dispatcherObjects[event as keyof typeof dispatcherObjects]; }, - [setActiveMainMenuElement] + [setActiveMainMenuElement, setAuthorizeUserPos] ); useEffect(() => { @@ -31,7 +38,7 @@ const MainMenuManager = (props: StateManagerProps) => { const dispatchedObject = dispatchObject(eventAction); if (dispatchedObject) { - dispatchedObject.action(dispatchedObject.value); + dispatchedObject.action(dispatchedObject.value as any); } } }, [dispatchObject, props.eventState]); diff --git a/src/core/StateManagers/SubSceneManager.tsx b/src/core/StateManagers/SubSceneManager.tsx new file mode 100644 index 0000000..596cf5b --- /dev/null +++ b/src/core/StateManagers/SubSceneManager.tsx @@ -0,0 +1,41 @@ +import { useCallback, useEffect } from "react"; +import { StateManagerProps } from "./EventManager"; +import { useBootStore } from "../../store"; + +const SubSceneManager = (props: StateManagerProps) => { + const setActiveBootSubScene = useBootStore( + (state) => state.setActiveBootSubScene + ); + + const dispatchObject = useCallback( + (event: string) => { + const dispatcherObjects = { + select_authorize_user: { + action: setActiveBootSubScene, + value: "authorize_user", + delay: 0, + }, + }; + return dispatcherObjects[event as keyof typeof dispatcherObjects]; + }, + [setActiveBootSubScene] + ); + + useEffect(() => { + if (props.eventState) { + const eventAction = props.eventState.event; + + const dispatchedObject = dispatchObject(eventAction); + + if (dispatchedObject) { + setTimeout(() => { + dispatchedObject.action(dispatchedObject.value); + }, dispatchedObject.delay); + } + } + }, [props.eventState, dispatchObject]); + + return null; +}; + +export default SubSceneManager; diff --git a/src/core/bootMainMenuEventHandler.ts b/src/core/bootMainMenuEventHandler.ts index 49f1de9..3c4c4da 100644 --- a/src/core/bootMainMenuEventHandler.ts +++ b/src/core/bootMainMenuEventHandler.ts @@ -3,11 +3,15 @@ import { GameContext } from "./StateManagers/EventManager"; const handleBootMainMenuEvent = (gameContext: GameContext) => { const keyPress = gameContext.keyPress; + const activeMainMenuElement = gameContext.activeMainMenuElement; + switch (keyPress) { case "down": return { event: "switch_to_load_data" }; case "up": return { event: "switch_to_authorize_user" }; + case "select": + return { event: `select_${activeMainMenuElement}` }; } }; diff --git a/src/scenes/BootScene.tsx b/src/scenes/BootScene.tsx index 5379269..7c5de0a 100644 --- a/src/scenes/BootScene.tsx +++ b/src/scenes/BootScene.tsx @@ -1,26 +1,39 @@ import React, { useEffect, useState } from "react"; import BootAccela from "../components/Boot/BootAccela"; import BootAnimation from "../components/Boot/BootAnimation"; -import BootMainMenu from "../components/Boot/BootMainMenu"; +import BootMainMenuComponents from "../components/Boot/BootMainMenuComponents"; +import { useBootStore } from "../store"; +import BootAuthorizeUser from "../components/Boot/BootAuthorizeUser"; const BootScene = () => { + const activeBootSubScene = useBootStore((state) => state.activeBootSubScene); + const [accelaVisible, setAccelaVisible] = useState(true); const [mainMenuVisible, setMainMenuVisible] = useState(false); useEffect(() => { setTimeout(() => { setAccelaVisible(false); - }, 2000); + // 2000 + }, 0); setTimeout(() => { setMainMenuVisible(true); - }, 6200); + //6200 + }, 0); }, []); return ( - - + + + ); }; diff --git a/src/store.ts b/src/store.ts index 65c42ef..a757cc3 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,6 +1,5 @@ import create from "zustand"; import { combine } from "zustand/middleware"; -import available_blue_orbs_on_projection from "./resources/available_blue_orbs_on_projection.json"; type SceneState = { currentScene: string; @@ -159,10 +158,17 @@ type ImageState = { }; }; -type MainMenuState ={ +type BootState = { + activeBootSubScene: string; + setActiveBootSubScene: (to: string) => void; +}; + +type MainMenuState = { activeMainMenuElement: string; + authorizeUserPos: { x: number; y: number }; + setAuthorizeUserPos: (to: { x: number; y: number }) => void; setActiveMainMenuElement: (to: string) => void; -} +}; export const useTextRendererStore = create((set) => ({ // yellow text @@ -389,10 +395,21 @@ export const useSceneStore = create((set) => ({ setScene: (to) => set(() => ({ currentScene: to })), })); -export const useMainMenuStore = create(set=> ({ +export const useBootStore = create((set) => ({ + activeBootSubScene: "authorize_user", + setActiveBootSubScene: (to) => set(() => ({ activeBootSubScene: to })), +})); + +export const useBootMainMenuStore = create((set) => ({ activeMainMenuElement: "authorize_user", - setActiveMainMenuElement: (to) => set(() => ({activeMainMenuElement: to})) -})) + authorizeUserPos: { x: 0, y: 0.5 }, + setActiveMainMenuElement: (to: string) => + set(() => ({ activeMainMenuElement: to })), + setAuthorizeUserPos: (to: { x: number; y: number }) => + set(() => ({ + authorizeUserPos: to, + })), +})); export const useImageStore = create( combine(