diff --git a/src/App.tsx b/src/App.tsx index 4fbf086..ef2c5f4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,6 @@ import MainScene from "./scenes/MainScene"; import "./static/css/main_scene.css"; import "./static/css/page.css"; import { Canvas } from "react-three-fiber"; -import Boot from "./components/Boot"; import MediaPlayer from "./components/MediaScene/MediaPlayer"; import MediaScene from "./scenes/MediaScene"; import EventManager from "./core/StateManagers/EventManager"; @@ -12,7 +11,6 @@ import GateScene from "./scenes/GateScene"; import BootScene from "./scenes/BootScene"; const App = () => { - const [moveToGame, setMoveToGame] = useState(false); const currentScene = useSceneStore((state) => state.currentScene); useEffect(() => { document.title = "< index >"; @@ -33,8 +31,6 @@ const App = () => { return (
- {/**/} - {/* {moveToGame ? : } */} diff --git a/src/components/Boot/BootAccela.tsx b/src/components/Boot/BootAccela.tsx index c8163e5..4960fcd 100644 --- a/src/components/Boot/BootAccela.tsx +++ b/src/components/Boot/BootAccela.tsx @@ -5,7 +5,11 @@ import { useFrame, useLoader } from "react-three-fiber"; import * as THREE from "three"; import { PlainAnimator } from "three-plain-animator/lib/plain-animator"; -const BootAccela = () => { +type BootAccelaProps = { + visible: boolean; +}; + +const BootAccela = (props: BootAccelaProps) => { const accelaBootTex: any = useLoader( THREE.TextureLoader, accelaBootSpriteSheet @@ -24,10 +28,18 @@ const BootAccela = () => { return ( <> - + - + diff --git a/src/components/Boot/BootAnimation.tsx b/src/components/Boot/BootAnimation.tsx index ecd7b8f..0fe5d68 100644 --- a/src/components/Boot/BootAnimation.tsx +++ b/src/components/Boot/BootAnimation.tsx @@ -8,12 +8,24 @@ import bootDangoText from "../../static/sprite/dango_text.png"; import bootMisoShio from "../../static/sprite/miso_shio.png"; import bootArrows from "../../static/sprite/boot_arrows.png"; import bootStatusTexts from "../../static/sprite/boot_status_texts.png"; +import bootBackgroundText from "../../static/sprite/boot_background_text.png"; +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; +}; + +const BootAnimation = (props: BootAnimationProps) => { + const [ + backgroundFloatingTextShown, + setBackgroundFloatingTextShown, + ] = useState(false); -const BootAnimation = () => { const bootLofTex = useLoader(THREE.TextureLoader, bootLof); const bootBottomBarLeftTex = useLoader( THREE.TextureLoader, @@ -29,6 +41,14 @@ const BootAnimation = () => { const bootMisoShioTex = useLoader(THREE.TextureLoader, bootMisoShio); const bootArrowsTex = useLoader(THREE.TextureLoader, bootArrows); const bootStatusTextsTex = useLoader(THREE.TextureLoader, bootStatusTexts); + const bootBackgroundTextTex = useLoader( + THREE.TextureLoader, + bootBackgroundText + ); + const bootBackgroundDistortedTextTex = useLoader( + THREE.TextureLoader, + bootBackgroundDistortedTex + ); const graySquareRef = useRef(); const arrowRef = useRef(); @@ -41,6 +61,45 @@ const BootAnimation = () => { arrowRef.current.position.y = arrowRef.current.position.y === -1.04 ? -0.96 : -1.04; } + + if ( + backgroundFloatingTextShown && + firstBackgroundTextRef.current && + sndBackgroundTextRef.current && + firstDistortedBackgroundTextRef.current && + sndDistortedBackgroundTextRef.current + ) { + if (firstBackgroundTextRef.current.position.y > 3.5) { + firstBackgroundTextRef.current.position.y = -3.5; + firstBackgroundTextRef.current.position.x = -0.85; + } else { + firstBackgroundTextRef.current.position.y += 0.01; + firstBackgroundTextRef.current.position.x += 0.001; + } + if (sndBackgroundTextRef.current.position.y > 3.5) { + sndBackgroundTextRef.current.position.y = -3.5; + sndBackgroundTextRef.current.position.x = -0.85; + } else { + sndBackgroundTextRef.current.position.y += 0.01; + sndBackgroundTextRef.current.position.x += 0.001; + } + + if (firstDistortedBackgroundTextRef.current.position.y > 2.8) { + firstDistortedBackgroundTextRef.current.position.y = -3; + firstDistortedBackgroundTextRef.current.position.x = 0; + } else { + firstDistortedBackgroundTextRef.current.position.y += 0.025; + firstDistortedBackgroundTextRef.current.position.x -= 0.013; + } + + if (sndDistortedBackgroundTextRef.current.position.y > 2.8) { + sndDistortedBackgroundTextRef.current.position.y = -3; + sndDistortedBackgroundTextRef.current.position.x = 0; + } else { + sndDistortedBackgroundTextRef.current.position.y += 0.025; + sndDistortedBackgroundTextRef.current.position.x -= 0.013; + } + } }); const currentBootStatusTextTex = useMemo(() => { @@ -50,45 +109,49 @@ const BootAnimation = () => { }, [bootStatusTextsTex]); useEffect(() => { - setTimeout(() => { - currentBootStatusTextTex.offset.y = 0.528; - }, 900); + if (props.visible) { + setTimeout(() => { + currentBootStatusTextTex.offset.y = 0.528; + }, 900); - setTimeout(() => { - currentBootStatusTextTex.offset.y = 0.79; - }, 1200); + setTimeout(() => { + currentBootStatusTextTex.offset.y = 0.79; + }, 1200); - setTimeout(() => { - currentBootStatusTextTex.offset.y = 0.264; - }, 1500); + setTimeout(() => { + currentBootStatusTextTex.offset.y = 0.264; + }, 1500); - setTimeout(() => { - currentBootStatusTextTex.offset.y = 0.79; - }, 1600); + setTimeout(() => { + currentBootStatusTextTex.offset.y = 0.79; + }, 1600); - setTimeout(() => { - currentBootStatusTextTex.offset.x = 0.5; - currentBootStatusTextTex.offset.y = 0.264; - }, 2100); + setTimeout(() => { + currentBootStatusTextTex.offset.x = 0.5; + currentBootStatusTextTex.offset.y = 0.264; + }, 2100); - setTimeout(() => { - currentBootStatusTextTex.offset.x = 0; - currentBootStatusTextTex.offset.y = 0.005; - }, 2400); + setTimeout(() => { + currentBootStatusTextTex.offset.x = 0; + currentBootStatusTextTex.offset.y = 0.005; + }, 2400); - setTimeout(() => { - currentBootStatusTextTex.offset.y = 0.79; - }, 2500); + setTimeout(() => { + currentBootStatusTextTex.offset.y = 0.79; + }, 2500); - setTimeout(() => { - currentBootStatusTextTex.offset.x = 0.5; - currentBootStatusTextTex.offset.y = 0.005; - setBootOpacity(0); - setGraySquarePosY(0); - setLofPosX(1.3); - setLofPosY(1); - }, 4000); - }, [currentBootStatusTextTex.offset]); + setTimeout(() => { + currentBootStatusTextTex.offset.x = 0.5; + currentBootStatusTextTex.offset.y = 0.005; + setBootOpacity(0); + setGraySquarePosY(0); + setLofPosX(1.3); + setLofPosY(1); + + setBackgroundFloatingTextShown(true); + }, 4200); + } + }, [bootBackgroundTextTex, currentBootStatusTextTex.offset, props.visible]); const [bootOpacity, setBootOpacity] = useState(1); const [graySquarePosY, setGraySquarePosY] = useState(-0.8); @@ -107,73 +170,150 @@ const BootAnimation = () => { config: { duration: 600 }, }); + const firstBackgroundTextRef = useRef(); + const sndBackgroundTextRef = useRef(); + const firstDistortedBackgroundTextRef = useRef(); + const sndDistortedBackgroundTextRef = useRef(); + return ( <> - - - - - - - - - - - - - - - - - - - - - + {props.visible ? ( + <> + {/*we have two of each to create looping effect*/} + + + + + + - - - + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) : ( + <> + )} ); }; diff --git a/src/components/Boot/BootMainMenu.tsx b/src/components/Boot/BootMainMenu.tsx new file mode 100644 index 0000000..086445b --- /dev/null +++ b/src/components/Boot/BootMainMenu.tsx @@ -0,0 +1,71 @@ +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/core/StateManagers/EventManager.tsx b/src/core/StateManagers/EventManager.tsx index accb20a..069ca8a 100644 --- a/src/core/StateManagers/EventManager.tsx +++ b/src/core/StateManagers/EventManager.tsx @@ -21,6 +21,7 @@ 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"; const getKeyCodeAssociation = (keyCode: number): string => { const keyCodeAssocs = { @@ -128,6 +129,7 @@ const EventManager = () => { + ); }; diff --git a/src/core/StateManagers/MainMenuManager.tsx b/src/core/StateManagers/MainMenuManager.tsx new file mode 100644 index 0000000..d68511a --- /dev/null +++ b/src/core/StateManagers/MainMenuManager.tsx @@ -0,0 +1,41 @@ +import { useCallback, useEffect } from "react"; +import { StateManagerProps } from "./EventManager"; +import { useMainMenuStore } from "../../store"; + +const MainMenuManager = (props: StateManagerProps) => { + const setActiveMainMenuElement = useMainMenuStore( + (state) => state.setActiveMainMenuElement + ); + + const dispatchObject = useCallback( + (event: string) => { + const dispatcherObjects = { + switch_to_load_data: { + action: setActiveMainMenuElement, + value: "load_data", + }, + switch_to_authorize_user: { + action: setActiveMainMenuElement, + value: "authorize_user", + }, + }; + + return dispatcherObjects[event as keyof typeof dispatcherObjects]; + }, + [setActiveMainMenuElement] + ); + + useEffect(() => { + if (props.eventState) { + const eventAction = props.eventState.event; + + const dispatchedObject = dispatchObject(eventAction); + if (dispatchedObject) { + dispatchedObject.action(dispatchedObject.value); + } + } + }, [dispatchObject, props.eventState]); + return null; +}; + +export default MainMenuManager; diff --git a/src/core/bootMainMenuEventHandler.ts b/src/core/bootMainMenuEventHandler.ts new file mode 100644 index 0000000..49f1de9 --- /dev/null +++ b/src/core/bootMainMenuEventHandler.ts @@ -0,0 +1,14 @@ +import { GameContext } from "./StateManagers/EventManager"; + +const handleBootMainMenuEvent = (gameContext: GameContext) => { + const keyPress = gameContext.keyPress; + + switch (keyPress) { + case "down": + return { event: "switch_to_load_data" }; + case "up": + return { event: "switch_to_authorize_user" }; + } +}; + +export default handleBootMainMenuEvent; diff --git a/src/core/computeAction.ts b/src/core/computeAction.ts index 51c165b..e2f445c 100644 --- a/src/core/computeAction.ts +++ b/src/core/computeAction.ts @@ -1,6 +1,7 @@ import { GameContext } from "./StateManagers/EventManager"; import handleMainSceneEvent from "./mainSceneEventHandler"; import handleMediaSceneEvent from "./mediaSceneEventHandler"; +import handleBootMainMenuEvent from "./bootMainMenuEventHandler"; const computeAction = (gameContext: GameContext) => { switch (gameContext.scene) { @@ -8,6 +9,8 @@ const computeAction = (gameContext: GameContext) => { return handleMainSceneEvent(gameContext); case "media": return handleMediaSceneEvent(gameContext); + case "boot": + return handleBootMainMenuEvent(gameContext); } }; diff --git a/src/scenes/BootScene.tsx b/src/scenes/BootScene.tsx index dcf0949..5379269 100644 --- a/src/scenes/BootScene.tsx +++ b/src/scenes/BootScene.tsx @@ -1,12 +1,26 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import BootAccela from "../components/Boot/BootAccela"; import BootAnimation from "../components/Boot/BootAnimation"; +import BootMainMenu from "../components/Boot/BootMainMenu"; const BootScene = () => { + const [accelaVisible, setAccelaVisible] = useState(true); + const [mainMenuVisible, setMainMenuVisible] = useState(false); + + useEffect(() => { + setTimeout(() => { + setAccelaVisible(false); + }, 2000); + setTimeout(() => { + setMainMenuVisible(true); + }, 6200); + }, []); + return ( - {/**/} - + + + ); }; diff --git a/src/store.ts b/src/store.ts index 71e36d0..65c42ef 100644 --- a/src/store.ts +++ b/src/store.ts @@ -159,6 +159,11 @@ type ImageState = { }; }; +type MainMenuState ={ + activeMainMenuElement: string; + setActiveMainMenuElement: (to: string) => void; +} + export const useTextRendererStore = create((set) => ({ // yellow text yellowText: "Play", @@ -384,6 +389,11 @@ export const useSceneStore = create((set) => ({ setScene: (to) => set(() => ({ currentScene: to })), })); +export const useMainMenuStore = create(set=> ({ + activeMainMenuElement: "authorize_user", + setActiveMainMenuElement: (to) => set(() => ({activeMainMenuElement: to})) +})) + export const useImageStore = create( combine( {