diff --git a/src/App.tsx b/src/App.tsx index 98a951f..70c29e3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -40,7 +40,6 @@ const App = () => {
- {dispatchScene[currentScene as keyof typeof dispatchScene]} diff --git a/src/components/MainScene/PauseSubscene/Pause.tsx b/src/components/MainScene/PauseSubscene/Pause.tsx index a8f1de3..ae96f51 100644 --- a/src/components/MainScene/PauseSubscene/Pause.tsx +++ b/src/components/MainScene/PauseSubscene/Pause.tsx @@ -4,6 +4,7 @@ import PauseSquare from "./PauseSquare"; import StaticBigLetter from "../../TextRenderer/StaticBigLetter"; import { usePauseStore } from "../../../store"; import { useLoader } from "react-three-fiber"; +import MainSceneEventManager from "../../../core/StateManagers/MainSceneEventManager"; const Pause = (props: { visible: boolean }) => { const exit = usePauseStore((state) => state.exitAnimation); @@ -341,6 +342,7 @@ const Pause = (props: { visible: boolean }) => { depthTest={false} /> + ) : ( diff --git a/src/components/MainScene/SyncedComponentLoader.tsx b/src/components/MainScene/SyncedComponentLoader.tsx index 0025db4..c0d5073 100644 --- a/src/components/MainScene/SyncedComponentLoader.tsx +++ b/src/components/MainScene/SyncedComponentLoader.tsx @@ -1,12 +1,12 @@ import React, { useEffect, useMemo, useState } from "react"; import HUD from "./SyncedComponents/HUD"; -import GreenTextRenderer from "../TextRenderer/GreenTextRenderer"; import YellowTextRenderer from "../TextRenderer/YellowTextRenderer"; import YellowOrb from "./SyncedComponents/YellowOrb"; import GrayPlanes from "./SyncedComponents/GrayPlanes"; import Starfield from "./SyncedComponents/Starfield"; import Site from "./SyncedComponents/Site"; import MiddleRing from "./SyncedComponents/MiddleRing"; +import MainSceneEventManager from "../../core/StateManagers/MainSceneEventManager"; type SyncedComponentLoaderProps = { paused: boolean; @@ -40,7 +40,6 @@ const SyncedComponentLoader = (props: SyncedComponentLoaderProps) => { <> - @@ -51,6 +50,7 @@ const SyncedComponentLoader = (props: SyncedComponentLoaderProps) => { introFinished={introFinished} /> + ); }; diff --git a/src/components/MainScene/SyncedComponents/GrayPlanes.tsx b/src/components/MainScene/SyncedComponents/GrayPlanes.tsx index 1563485..4c0c383 100644 --- a/src/components/MainScene/SyncedComponents/GrayPlanes.tsx +++ b/src/components/MainScene/SyncedComponents/GrayPlanes.tsx @@ -1,54 +1,33 @@ -import React, { createRef, memo, RefObject, useRef } from "react"; +import React, { useMemo, useRef } from "react"; import * as THREE from "three"; import { useFrame } from "react-three-fiber"; +import GrayPlane from "./GrayPlanes/GrayPlane"; const GrayPlanes = () => { const grayPlaneGroupRef = useRef(); - const grayPlanePoses = [ - [1.2, 0, -1.2], - [1.2, 0, 1.2], - [1.2, 0, -0.5], - [-1.2, 0, -1.2], - [-1.2, 0, 1.2], - [-1.2, 0, 1], - [0.5, 0, 1], - ]; - - const grayPlaneRefs = grayPlanePoses.map((poses: number[]) => - // eslint-disable-next-line react-hooks/rules-of-hooks - useRef[]>( - poses.map(() => createRef()) - ) + const grayPlanePoses = useMemo( + () => [ + [1.2, 0, -1.2], + [1.2, 0, 1.2], + [1.2, 0, -0.5], + [-1.2, 0, -1.2], + [-1.2, 0, 1.2], + [-1.2, 0, 1], + [0.5, 0, 1], + ], + [] ); useFrame(() => { grayPlaneGroupRef.current!.rotation.y -= 0.01; - grayPlaneRefs.forEach((ref: any) => (ref.current!.rotation.y += 0.03)); }); return ( - // separate wrapper group to make it rotate around [0,0,0] - {grayPlaneRefs.map((ref, idx: number) => { - return ( - - - - - ); - })} + {grayPlanePoses.map((pos, idx: number) => ( + + ))} ); }; diff --git a/src/components/MainScene/SyncedComponents/GrayPlanes/GrayPlane.tsx b/src/components/MainScene/SyncedComponents/GrayPlanes/GrayPlane.tsx new file mode 100644 index 0000000..f389cbf --- /dev/null +++ b/src/components/MainScene/SyncedComponents/GrayPlanes/GrayPlane.tsx @@ -0,0 +1,35 @@ +import React, { useRef } from "react"; +import * as THREE from "three"; +import { useFrame } from "react-three-fiber"; + +type GrayPlaneProps = { + position: [number, number, number]; +}; + +const GrayPlane = (props: GrayPlaneProps) => { + const meshRef = useRef(); + + useFrame(() => { + if (meshRef.current) { + meshRef.current.rotation.y += 0.03; + } + }); + + return ( + + + + + ); +}; + +export default GrayPlane; diff --git a/src/components/MainScene/SyncedComponents/HUD.tsx b/src/components/MainScene/SyncedComponents/HUD.tsx index 509b1a4..5252966 100644 --- a/src/components/MainScene/SyncedComponents/HUD.tsx +++ b/src/components/MainScene/SyncedComponents/HUD.tsx @@ -1,4 +1,4 @@ -import React, { memo } from "react"; +import React, { useMemo } from "react"; import { useLoader } from "react-three-fiber"; import * as THREE from "three"; import bigHud from "../../../static/sprite/big_hud.png"; @@ -8,19 +8,39 @@ import longHudMirrored from "../../../static/sprite/long_hud_mirrored.png"; import boringHud from "../../../static/sprite/long_hud_boring.png"; import boringHudMirrored from "../../../static/sprite/long_hud_boring_mirrored.png"; import { a, useSpring } from "@react-spring/three"; -import { useHudStore } from "../../../store"; +import { useHudStore, useNodeStore, useSiteStore } from "../../../store"; import node_huds from "../../../resources/node_huds.json"; +import MediumLetter from "../../TextRenderer/MediumLetter"; +import site_a from "../../../resources/site_a.json"; +import site_b from "../../../resources/site_b.json"; +import { SiteType } from "./Site"; const HUD = () => { + const activeNodeId = useNodeStore((state) => state.activeNodeState.id); + const currentSite = useSiteStore((state) => state.currentSite); + + const greenText = useMemo(() => { + if (activeNodeId === "UNKNOWN") return "".split(""); + else { + const siteData = currentSite === "a" ? site_a : site_b; + const level = activeNodeId.substr(0, 2); + + return (siteData as SiteType)[level][activeNodeId].title.split(""); + } + }, [activeNodeId, currentSite]); + const active = useHudStore((state) => state.active); const id = useHudStore((state) => state.id); - const currentHud = node_huds[id as keyof typeof node_huds]; + const currentHud = useMemo(() => node_huds[id as keyof typeof node_huds], [ + id, + ]); const hudElementState = useSpring({ bigHUDPositionX: active, longHUDPositionX: active, boringHUDPositionX: active, + greenTextPositionX: active, config: { duration: 400 }, }); @@ -39,9 +59,14 @@ const HUD = () => { [currentHud.long.initial_position[0], currentHud.long.position[0]] ); - // these hud elements come in all shapes and forms, some of them are mirrored, rotated - // you name it. this function allows me to specify whether i want a normal texture - // for the blue orb or the mirrored/rotated one. + const greenTextPosX = hudElementState.greenTextPositionX.to( + [0, 1], + [ + currentHud.medium_text.initial_position[0], + currentHud.medium_text.position[0], + ] + ); + const spriteTypeToSprite = (spriteType: string, hudElement: string) => { switch (spriteType) { case "normal": @@ -85,8 +110,8 @@ const HUD = () => { @@ -99,8 +124,8 @@ const HUD = () => { @@ -113,8 +138,8 @@ const HUD = () => { @@ -125,6 +150,16 @@ const HUD = () => { depthTest={false} /> + + {greenText.map((letter, idx) => ( + + ))} + ); }; diff --git a/src/components/MainScene/SyncedComponents/MiddleRing.tsx b/src/components/MainScene/SyncedComponents/MiddleRing.tsx index ad10ca9..943d2d9 100644 --- a/src/components/MainScene/SyncedComponents/MiddleRing.tsx +++ b/src/components/MainScene/SyncedComponents/MiddleRing.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useRef } from "react"; +import React, { useMemo, useRef } from "react"; import { useFrame, useLoader } from "react-three-fiber"; import middleRingTexture from "../../../static/sprite/middle_ring_tex.png"; import * as THREE from "three"; @@ -14,8 +14,6 @@ const MiddleRing = () => { const animDuration = useMiddleRingStore((state) => state.animDuration); const mainRingVisible = useMiddleRingStore((state) => state.mainRingVisible); - const partSeparatorVal = useMiddleRingStore(state=> state.partSeparatorVal) - const wobbleState = useSpring({ wobbleStrength: transformState.wobbleStrength, noiseStrength: transformState.noiseStrength, @@ -198,8 +196,10 @@ const MiddleRing = () => { middleRingMaterialRef.current.needsUpdate = true; } - if (rotating && middleRingRef && middleRingPartRef) { + if (rotating && middleRingRef.current) { middleRingRef.current!.rotation.y += 0.05; + } + if (rotating && middleRingPartRef.current) { middleRingPartRef.current!.rotation.y += 0.05; } }); @@ -229,23 +229,26 @@ const MiddleRing = () => { /> - - {[...Array(30).keys()].map((i) => { - const angle = (i / 30) * 2 * Math.PI; - return ( - - ); - })} - + {!mainRingVisible ? ( + + {[...Array(30).keys()].map((i) => { + const angle = (i / 30) * 2 * Math.PI; + return ( + + ); + })} + + ) : ( + <> + )} ); }; diff --git a/src/components/TextRenderer/BigLetter.tsx b/src/components/TextRenderer/BigLetter.tsx index a2823c4..70729b1 100644 --- a/src/components/TextRenderer/BigLetter.tsx +++ b/src/components/TextRenderer/BigLetter.tsx @@ -5,13 +5,13 @@ import * as THREE from "three"; import { useLoader } from "react-three-fiber"; import orange_font_json from "../../resources/font_data/big_font.json"; import { a, useSpring } from "@react-spring/three"; -import React, { useMemo } from "react"; +import React, { useEffect, useMemo } from "react"; +import { useBigTextStore } from "../../store"; const BigLetter = (props: { color: string; letter: string; letterIdx: number; - xOffsetCoeff: number; }) => { const colorToTexture = (color: string) => { const colorTexture = { @@ -89,17 +89,23 @@ const BigLetter = (props: { return geometry; }, [letterData, lineYOffsets, props.letter]); - const textRendererState = useSpring({ - letterOffsetXCoeff: - props.letterIdx + - 0.3 + - (props.letterIdx + 0.3) * props.xOffsetCoeff, + const [{ letterOffsetX }, set] = useSpring(() => ({ + letterOffsetX: props.letterIdx + 0.3 + (props.letterIdx + 0.3), config: { duration: 200 }, - }); + })); + + useEffect(() => { + useBigTextStore.subscribe(set, (state) => ({ + letterOffsetX: + props.letterIdx + + 0.3 + + (props.letterIdx + 0.3) * state.transformState.xOffset, + })); + }, [props.letterIdx, set]); return ( { - const greenTextActive = useGreenTextStore((state) => state.active); - - const transformRef = useRef(useGreenTextStore.getState().transformState); - - const textArrRef = useRef(useGreenTextStore.getState().text.split("")); - - const { greenTextPosXToggle } = useSpring({ - greenTextPosXToggle: greenTextActive, - config: { duration: 400 }, - }); - - const greenTextPosX = greenTextPosXToggle.to( - [0, 1], - [transformRef.current.posX.initial, transformRef.current.posX.final] - ); - - // subscribing to state and updating transiently - useEffect( - () => - useGreenTextStore.subscribe( - (state) => { - transformRef.current = (state as GreenTextState).transformState; - textArrRef.current = (state as GreenTextState).text.split(""); - }, - (state) => state - ), - [] - ); - - return ( - - - {textArrRef.current.map((letter, idx) => ( - - ))} - - - ); -}; - -export default GreenTextRenderer; diff --git a/src/components/TextRenderer/MediaYellowTextAnimator.tsx b/src/components/TextRenderer/MediaYellowTextAnimator.tsx index 9a4f6fe..8caf6f5 100644 --- a/src/components/TextRenderer/MediaYellowTextAnimator.tsx +++ b/src/components/TextRenderer/MediaYellowTextAnimator.tsx @@ -1,17 +1,24 @@ -import React from "react"; +import React, { useEffect, useRef } from "react"; import { useMediaBigTextStore } from "../../store"; import { a, useTrail } from "@react-spring/three"; import BigLetter from "./BigLetter"; const MediaYellowTextAnimator = () => { - const transformState = useMediaBigTextStore((state) => state.transformState); - const textArr = useMediaBigTextStore((state) => state.text).split(""); + const textArrRef = useRef(useMediaBigTextStore.getState().text.split("")); - const trail = useTrail(textArr.length, { - posX: transformState.posX, - posY: transformState.posY, - config: { duration: 280 }, - }); + const [trail, set] = useTrail(textArrRef.current.length, () => ({ + posX: 0, + posY: 0, + xOffset: 0, + config: { duration: 200 }, + })); + + useEffect(() => { + useMediaBigTextStore.subscribe(set, (state) => ({ + posX: state.transformState.posX, + posY: state.transformState.posY, + })); + }, [set]); return ( @@ -25,8 +32,7 @@ const MediaYellowTextAnimator = () => { > diff --git a/src/components/TextRenderer/YellowTextRenderer.tsx b/src/components/TextRenderer/YellowTextRenderer.tsx index 73abf53..d8dc0ab 100644 --- a/src/components/TextRenderer/YellowTextRenderer.tsx +++ b/src/components/TextRenderer/YellowTextRenderer.tsx @@ -1,82 +1,45 @@ import React, { useEffect, useRef } from "react"; -import { BigTextState, useBigTextStore } from "../../store"; +import { BigTextState, useBigTextStore, useNodeStore } from "../../store"; import { a, useSpring, useTrail } from "@react-spring/three"; import BigLetter from "./BigLetter"; const YellowTextRenderer = () => { - const disableTrail = useBigTextStore((state) => state.disableTrail); - const transformState = useBigTextStore((state) => state.transformState); - const visible = useBigTextStore((state) => state.visible); const color = useBigTextStore((state) => state.color); const textArrRef = useRef(useBigTextStore.getState().text.split("")); - const transformRef = useRef(useBigTextStore.getState().transformState); - - // this is used to animate the letters moving one after another - const trail = useTrail(textArrRef.current.length, { - posX: transformRef.current.posX, - posY: transformRef.current.posY, + const [trail, set] = useTrail(textArrRef.current.length, () => ({ + posX: 0, + posY: 0, config: { duration: 280 }, - }); + })); - // this is used when the whole GROUP itself needs to be animated - const spring = useSpring({ - posX: transformState.posX, - posY: transformState.posY, - config: { duration: 1200 }, - }); - - useEffect( - () => - useBigTextStore.subscribe( - (state) => { - transformRef.current = (state as BigTextState).transformState; - textArrRef.current = (state as BigTextState).text.split(""); - }, - (state) => state - ), - [] - ); + useEffect(() => { + useBigTextStore.subscribe(set, (state) => ({ + posX: state.transformState.posX, + posY: state.transformState.posY, + })); + }, [set]); return ( - {disableTrail - ? textArrRef.current.map((letter, idx) => ( - - - - )) - : trail.map(({ posX, posY }, idx) => ( - - - - ))} + {trail.map(({ posX, posY }, idx) => ( + + + + ))} ); }; diff --git a/src/core/StateManagers/BootAuthorizeUserManager.tsx b/src/core/StateManagers/BootSceneManagers/BootAuthorizeUserManager.tsx similarity index 93% rename from src/core/StateManagers/BootAuthorizeUserManager.tsx rename to src/core/StateManagers/BootSceneManagers/BootAuthorizeUserManager.tsx index a9969c3..12d10ac 100644 --- a/src/core/StateManagers/BootAuthorizeUserManager.tsx +++ b/src/core/StateManagers/BootSceneManagers/BootAuthorizeUserManager.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { StateManagerProps } from "./EventManager"; -import { useAuthorizeUserStore, useBootStore } from "../../store"; +import { StateManagerProps } from "../EventManager"; +import { useAuthorizeUserStore, useBootStore } from "../../../store"; const BootAuthorizeUserManager = (props: StateManagerProps) => { const setActiveLetterTextureOffset = useAuthorizeUserStore( diff --git a/src/core/StateManagers/BootComponentManager.tsx b/src/core/StateManagers/BootSceneManagers/BootComponentManager.tsx similarity index 94% rename from src/core/StateManagers/BootComponentManager.tsx rename to src/core/StateManagers/BootSceneManagers/BootComponentManager.tsx index 18e1278..3cc4878 100644 --- a/src/core/StateManagers/BootComponentManager.tsx +++ b/src/core/StateManagers/BootSceneManagers/BootComponentManager.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { StateManagerProps } from "./EventManager"; -import { useBootStore } from "../../store"; +import { StateManagerProps } from "../EventManager"; +import { useBootStore } from "../../../store"; const BootComponentManager = (props: StateManagerProps) => { const toggleComponentMatrixIdx = useBootStore( diff --git a/src/core/StateManagers/EventManager.tsx b/src/core/StateManagers/EventManager.tsx index db1dc9b..d479d93 100644 --- a/src/core/StateManagers/EventManager.tsx +++ b/src/core/StateManagers/EventManager.tsx @@ -18,24 +18,23 @@ import { useSiteStore, useSSknStore, } from "../../store"; -import GreenTextManager from "./MainSceneManagers/GreenTextManager"; import MediaComponentManager from "./MediaSceneManagers/MediaComponentManager"; -import SceneManager from "./SceneManager"; +import SceneManager from "./GameManagers/SceneManager"; import YellowTextManager from "./MainSceneManagers/YellowTextManager"; import LevelManager from "./MainSceneManagers/LevelManager"; -import BootComponentManager from "./BootComponentManager"; -import SSknComponentManager from "./SSknComponentManager"; +import BootComponentManager from "./BootSceneManagers/BootComponentManager"; +import SSknComponentManager from "./SSknSceneManagers/SSknComponentManager"; import handleMainSceneEvent from "../mainSceneEventHandler"; import handleMediaSceneEvent from "../mediaSceneEventHandler"; import handleBootEvent from "../bootEventHandler"; import handleSSknSceneEvent from "../ssknSceneEventHandler"; -import BootAuthorizeUserManager from "./BootAuthorizeUserManager"; +import BootAuthorizeUserManager from "./BootSceneManagers/BootAuthorizeUserManager"; import LevelSelectionManager from "./MainSceneManagers/LevelSelectionManager"; -import SubsceneManager from "./SubsceneManager"; +import SubsceneManager from "./GameManagers/SubsceneManager"; import PauseComponentManager from "./MainSceneManagers/PauseComponentManager"; -import MediaYellowTextManager from "./MediaYellowTextManager"; -import GameSaver from "./GameSaver"; -import GameLoader from "./GameLoader"; +import MediaYellowTextManager from "./MediaSceneManagers/MediaYellowTextManager"; +import GameSaver from "./GameManagers/GameSaver"; +import GameLoader from "./GameManagers/GameLoader"; import { useFrame } from "react-three-fiber"; import IdleManager from "./MainSceneManagers/IdleManager"; @@ -279,7 +278,6 @@ const EventManager = () => { <> - diff --git a/src/core/StateManagers/GameLoader.tsx b/src/core/StateManagers/GameManagers/GameLoader.tsx similarity index 93% rename from src/core/StateManagers/GameLoader.tsx rename to src/core/StateManagers/GameManagers/GameLoader.tsx index 132170f..787de9e 100644 --- a/src/core/StateManagers/GameLoader.tsx +++ b/src/core/StateManagers/GameManagers/GameLoader.tsx @@ -7,12 +7,12 @@ import { useNodeStore, useSiteSaveStore, useSiteStore, -} from "../../store"; -import { StateManagerProps } from "./EventManager"; -import node_huds from "./../../resources/node_huds.json"; -import site_a from "./../../resources/site_a.json"; -import site_b from "./../../resources/site_b.json"; -import { SiteType } from "../../components/MainScene/SyncedComponents/Site"; +} from "../../../store"; +import { StateManagerProps } from "../EventManager"; +import node_huds from "../../../resources/node_huds.json"; +import site_a from "../../../resources/site_a.json"; +import site_b from "../../../resources/site_b.json"; +import { SiteType } from "../../../components/MainScene/SyncedComponents/Site"; const GameLoader = (props: StateManagerProps) => { const siteASaveState = useSiteSaveStore((state) => state.a); diff --git a/src/core/StateManagers/GameSaver.tsx b/src/core/StateManagers/GameManagers/GameSaver.tsx similarity index 93% rename from src/core/StateManagers/GameSaver.tsx rename to src/core/StateManagers/GameManagers/GameSaver.tsx index 2d46ae0..a0538f2 100644 --- a/src/core/StateManagers/GameSaver.tsx +++ b/src/core/StateManagers/GameManagers/GameSaver.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { useSiteSaveStore } from "../../store"; -import { StateManagerProps } from "./EventManager"; +import { useSiteSaveStore } from "../../../store"; +import { StateManagerProps } from "../EventManager"; const GameSaver = (props: StateManagerProps) => { const setSiteSaveState = useSiteSaveStore((state) => state.setSiteSaveState); diff --git a/src/core/StateManagers/SceneManager.tsx b/src/core/StateManagers/GameManagers/SceneManager.tsx similarity index 95% rename from src/core/StateManagers/SceneManager.tsx rename to src/core/StateManagers/GameManagers/SceneManager.tsx index 5c7b4a8..d44c0a2 100644 --- a/src/core/StateManagers/SceneManager.tsx +++ b/src/core/StateManagers/GameManagers/SceneManager.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { StateManagerProps } from "./EventManager"; -import { useMainSceneStore, useSceneStore } from "../../store"; +import { StateManagerProps } from "../EventManager"; +import { useMainSceneStore, useSceneStore } from "../../../store"; const SceneManager = (props: StateManagerProps) => { const setScene = useSceneStore((state) => state.setScene); diff --git a/src/core/StateManagers/SubsceneManager.tsx b/src/core/StateManagers/GameManagers/SubsceneManager.tsx similarity index 94% rename from src/core/StateManagers/SubsceneManager.tsx rename to src/core/StateManagers/GameManagers/SubsceneManager.tsx index 59cf632..3c880f8 100644 --- a/src/core/StateManagers/SubsceneManager.tsx +++ b/src/core/StateManagers/GameManagers/SubsceneManager.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { StateManagerProps } from "./EventManager"; -import { useBootStore, useMainSceneStore } from "../../store"; +import { StateManagerProps } from "../EventManager"; +import { useBootStore, useMainSceneStore } from "../../../store"; const SubsceneManager = (props: StateManagerProps) => { const setMainSubscene = useMainSceneStore((state) => state.setSubscene); diff --git a/src/core/StateManagers/GateSceneManager.tsx b/src/core/StateManagers/GateSceneManager.tsx new file mode 100644 index 0000000..036b0ce --- /dev/null +++ b/src/core/StateManagers/GateSceneManager.tsx @@ -0,0 +1,42 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { getKeyCodeAssociation } from "../utils/keyPressUtils"; +import SceneManager from "./GameManagers/SceneManager"; + +const GateSceneManager = () => { + const [eventState, setEventState] = useState(); + + const [loaded, setLoaded] = useState(false); + + useEffect(() => { + setTimeout(() => { + setLoaded(true); + + return () => { + setLoaded(false); + }; + }, 3500); + }, []); + + const handleKeyPress = useCallback((event) => { + const { keyCode } = event; + + const keyPress = getKeyCodeAssociation(keyCode); + + if (keyPress && loaded) { + const event = { event: "exit_gate" }; + setEventState(event); + } + }, [loaded]); + + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, [handleKeyPress]); + + return ; +}; + +export default GateSceneManager; diff --git a/src/core/StateManagers/MainSceneEventManager.tsx b/src/core/StateManagers/MainSceneEventManager.tsx new file mode 100644 index 0000000..175f282 --- /dev/null +++ b/src/core/StateManagers/MainSceneEventManager.tsx @@ -0,0 +1,119 @@ +import React, { useCallback, useEffect, useRef, useState } from "react"; +import { + useLevelSelectionStore, + useLevelStore, + useMainSceneStore, + useNodeStore, + usePauseStore, + useSiteStore, +} from "../../store"; +import handleMainSceneEvent from "../mainSceneEventHandler"; +import { getKeyCodeAssociation } from "../utils/keyPressUtils"; +import NodeManager from "./MainSceneManagers/NodeManager"; +import NodeHUDManager from "./MainSceneManagers/NodeHUDManager"; +import SiteManager from "./MainSceneManagers/SiteManager"; +import LainManager from "./MainSceneManagers/LainManager"; +import MiddleRingManager from "./MainSceneManagers/MiddleRingManager"; +import SceneManager from "./GameManagers/SceneManager"; +import YellowTextManager from "./MainSceneManagers/YellowTextManager"; +import LevelManager from "./MainSceneManagers/LevelManager"; +import LevelSelectionManager from "./MainSceneManagers/LevelSelectionManager"; +import SubsceneManager from "./GameManagers/SubsceneManager"; +import PauseComponentManager from "./MainSceneManagers/PauseComponentManager"; +import GameSaver from "./GameManagers/GameSaver"; +import GameLoader from "./GameManagers/GameLoader"; +import IdleManager from "./MainSceneManagers/IdleManager"; + +type MainSceneEventManagerProps = { + loaded: boolean; +}; + +const MainSceneEventManager = (props: MainSceneEventManagerProps) => { + // all the possible context needed to calculate new state + const currentSite = useSiteStore((state) => state.currentSite); + const activeNodeId = useNodeStore((state) => state.activeNodeState.id); + const nodeMatrixIndices = useNodeStore((state) => state.nodeMatrixIndices); + const siteTransformState = useSiteStore((state) => state.transformState); + const activeLevel = useLevelStore((state) => state.activeLevel); + const mainSubscene = useMainSceneStore((state) => state.subscene); + const selectedLevel = useLevelSelectionStore((state) => state.selectedLevel); + const pauseMatrixIdx = usePauseStore((state) => state.componentMatrixIdx); + const activePauseComponent = usePauseStore( + useCallback((state) => state.componentMatrix[pauseMatrixIdx], [ + pauseMatrixIdx, + ]) + ); + const gameProgress = useNodeStore((state) => state.gameProgress); + + const timePassedSinceLastKeyPress = useRef(-1); + + const [eventState, setEventState] = useState(); + + const handleKeyPress = useCallback( + (event) => { + const { keyCode } = event; + + const keyPress = getKeyCodeAssociation(keyCode); + + if (keyPress && props.loaded) { + timePassedSinceLastKeyPress.current = Date.now() + 2500; + const event = handleMainSceneEvent({ + mainSubscene: mainSubscene, + keyPress: keyPress, + siteTransformState: siteTransformState, + activeNodeId: activeNodeId, + nodeMatrixIndices: nodeMatrixIndices, + activeLevel: activeLevel, + selectedLevel: selectedLevel, + pauseMatrixIdx: pauseMatrixIdx, + activePauseComponent: activePauseComponent, + gameProgress: gameProgress, + currentSite: currentSite, + }); + setEventState(event); + } + }, + [ + props.loaded, + mainSubscene, + siteTransformState, + activeNodeId, + nodeMatrixIndices, + activeLevel, + selectedLevel, + pauseMatrixIdx, + activePauseComponent, + gameProgress, + currentSite, + ] + ); + + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, [handleKeyPress]); + + return ( + <> + + + + + + + + + + + + + + + + ); +}; + +export default MainSceneEventManager; diff --git a/src/core/StateManagers/MainSceneManagers/GreenTextManager.tsx b/src/core/StateManagers/MainSceneManagers/GreenTextManager.tsx deleted file mode 100644 index 00b7282..0000000 --- a/src/core/StateManagers/MainSceneManagers/GreenTextManager.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { useCallback, useEffect } from "react"; -import { StateManagerProps } from "../EventManager"; -import node_huds from "../../../resources/node_huds.json"; -import site_a from "../../../resources/site_a.json"; -import { SiteType } from "../../../components/MainScene/SyncedComponents/Site"; -import { useGreenTextStore, useSiteStore } from "../../../store"; -import site_b from "../../../resources/site_b.json"; - -const GreenTextManager = (props: StateManagerProps) => { - const setGreenText = useGreenTextStore((state) => state.setText); - const toggleActive = useGreenTextStore((state) => state.toggleActive); - const setTransformState = useGreenTextStore( - (state) => state.setTransformState - ); - - const currentSite = useSiteStore((state) => state.currentSite); - - const siteData = currentSite === "a" ? site_a : site_b; - - const toggleAndSetGreenText = useCallback( - ( - newActiveNodeId: string, - newActiveHudId: string, - newLevel: string, - delay: number, - shouldToggleAtStart: boolean - ) => { - const targetGreenText = - newActiveNodeId === "UNKNOWN" - ? "" - : (siteData as SiteType)[newLevel][newActiveNodeId].title; - - const targetGreenTextPosData = - node_huds[newActiveHudId as keyof typeof node_huds].medium_text; - - if (shouldToggleAtStart) toggleActive(); - - setTimeout(() => { - setTransformState( - { - initial: targetGreenTextPosData.initial_position[0], - final: targetGreenTextPosData.position[0], - }, - "posX" - ); - setTransformState(targetGreenTextPosData.position[1], "posY"); - setGreenText(targetGreenText); - toggleActive(); - }, delay); - }, - [setGreenText, setTransformState, siteData, toggleActive] - ); - - const dispatchObject = useCallback( - (eventState: { - event: string; - activeNodeId: string; - activeHudId: string; - level: string; - }) => { - switch (eventState.event) { - case "site_up": - case "site_down": - case "site_left": - case "site_right": - return { - action: toggleAndSetGreenText, - value: [ - eventState.activeNodeId, - eventState.activeHudId, - eventState.level, - 3900, - true, - ], - }; - case "change_node": - return { - action: toggleAndSetGreenText, - value: [ - eventState.activeNodeId, - eventState.activeHudId, - eventState.level, - 500, - true, - ], - }; - case "toggle_level_selection": - case "level_selection_back": - return { - action: toggleActive, - }; - case "select_level_up": - case "select_level_down": - return { - action: toggleAndSetGreenText, - value: [ - eventState.activeNodeId, - eventState.activeHudId, - eventState.level, - 3900, - false, - ], - }; - } - }, - [toggleActive, toggleAndSetGreenText] - ); - - useEffect(() => { - if (props.eventState) { - const dispatchedObject = dispatchObject(props.eventState); - - if (dispatchedObject) { - (dispatchedObject.action as any).apply( - null, - dispatchedObject.value as any - ); - } - } - }, [props.eventState, dispatchObject]); - return null; -}; - -export default GreenTextManager; diff --git a/src/core/StateManagers/MediaSceneEventManager.tsx b/src/core/StateManagers/MediaSceneEventManager.tsx new file mode 100644 index 0000000..895d36a --- /dev/null +++ b/src/core/StateManagers/MediaSceneEventManager.tsx @@ -0,0 +1,71 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { useMediaStore, useMediaWordStore } from "../../store"; +import { getKeyCodeAssociation } from "../utils/keyPressUtils"; +import SceneManager from "./GameManagers/SceneManager"; +import handleMediaSceneEvent from "../mediaSceneEventHandler"; +import MediaComponentManager from "./MediaSceneManagers/MediaComponentManager"; +import MediaYellowTextManager from "./MediaSceneManagers/MediaYellowTextManager"; + +const MediaSceneEventManager = () => { + // all the possible context needed to calculate new state + const mediaComponentMatrixIndices = useMediaStore( + (state) => state.componentMatrixIndices + ); + + const activeMediaComponent = useMediaStore( + useCallback( + (state) => + state.componentMatrix[mediaComponentMatrixIndices.sideIdx][ + mediaComponentMatrixIndices.sideIdx === 0 + ? mediaComponentMatrixIndices.leftSideIdx + : mediaComponentMatrixIndices.rightSideIdx + ], + [mediaComponentMatrixIndices] + ) + ); + const rightSideComponentIdx = useMediaStore( + (state) => state.componentMatrixIndices.rightSideIdx + ); + + const wordPosStateIdx = useMediaWordStore((state) => state.posStateIdx); + + const [eventState, setEventState] = useState(); + + const handleKeyPress = useCallback( + (event) => { + const { keyCode } = event; + + const keyPress = getKeyCodeAssociation(keyCode); + + if (keyPress) { + const event = handleMediaSceneEvent({ + keyPress: keyPress, + activeMediaComponent: activeMediaComponent, + wordPosStateIdx: wordPosStateIdx, + rightSideComponentIdx: rightSideComponentIdx, + }); + + setEventState(event); + } + }, + [activeMediaComponent, rightSideComponentIdx, wordPosStateIdx] + ); + + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, [handleKeyPress]); + + return ( + <> + + + + + ); +}; + +export default MediaSceneEventManager; diff --git a/src/core/StateManagers/MediaYellowTextManager.tsx b/src/core/StateManagers/MediaSceneManagers/MediaYellowTextManager.tsx similarity index 94% rename from src/core/StateManagers/MediaYellowTextManager.tsx rename to src/core/StateManagers/MediaSceneManagers/MediaYellowTextManager.tsx index 9da6b19..373fcd6 100644 --- a/src/core/StateManagers/MediaYellowTextManager.tsx +++ b/src/core/StateManagers/MediaSceneManagers/MediaYellowTextManager.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { useMediaBigTextStore } from "../../store"; -import { StateManagerProps } from "./EventManager"; +import { useMediaBigTextStore } from "../../../store"; +import { StateManagerProps } from "../EventManager"; const MediaYellowTextManager = (props: StateManagerProps) => { const setTransformState = useMediaBigTextStore( diff --git a/src/core/StateManagers/SSknSceneManager.tsx b/src/core/StateManagers/SSknSceneManager.tsx new file mode 100644 index 0000000..36a425b --- /dev/null +++ b/src/core/StateManagers/SSknSceneManager.tsx @@ -0,0 +1,55 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { getKeyCodeAssociation } from "../utils/keyPressUtils"; +import SceneManager from "./GameManagers/SceneManager"; +import handleSSknSceneEvent from "../ssknSceneEventHandler"; +import { useSSknStore } from "../../store"; +import SSknComponentManager from "./SSknSceneManagers/SSknComponentManager"; + +const SSknSceneManager = () => { + // all the possible context needed to calculate new state + const ssknComponentMatrixIdx = useSSknStore( + (state) => state.componentMatrixIdx + ); + const activeSSknComponent = useSSknStore( + useCallback((state) => state.componentMatrix[ssknComponentMatrixIdx], [ + ssknComponentMatrixIdx, + ]) + ); + + const [eventState, setEventState] = useState(); + + const handleKeyPress = useCallback( + (event) => { + const { keyCode } = event; + + const keyPress = getKeyCodeAssociation(keyCode); + + if (keyPress) { + const event = handleSSknSceneEvent({ + keyPress: keyPress, + activeSSknComponent: activeSSknComponent, + }); + + setEventState(event); + } + }, + [activeSSknComponent] + ); + + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, [handleKeyPress]); + + return ( + <> + + + + ); +}; + +export default SSknSceneManager; diff --git a/src/core/StateManagers/SSknComponentManager.tsx b/src/core/StateManagers/SSknSceneManagers/SSknComponentManager.tsx similarity index 90% rename from src/core/StateManagers/SSknComponentManager.tsx rename to src/core/StateManagers/SSknSceneManagers/SSknComponentManager.tsx index b0ec694..6edbcf4 100644 --- a/src/core/StateManagers/SSknComponentManager.tsx +++ b/src/core/StateManagers/SSknSceneManagers/SSknComponentManager.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect } from "react"; -import { StateManagerProps } from "./EventManager"; -import { useMediaStore, useSSknStore } from "../../store"; +import { StateManagerProps } from "../EventManager"; +import { useMediaStore, useSSknStore } from "../../../store"; const SSknComponentManager = (props: StateManagerProps) => { const toggleComponentMatrixIdx = useSSknStore( diff --git a/src/core/utils/keyPressUtils.ts b/src/core/utils/keyPressUtils.ts new file mode 100644 index 0000000..9d1da9e --- /dev/null +++ b/src/core/utils/keyPressUtils.ts @@ -0,0 +1,14 @@ +export const getKeyCodeAssociation = (keyCode: number) => { + const keyCodeAssocs = { + 40: "DOWN", // down arrow + 37: "LEFT", // left arrow + 38: "UP", // up arrow + 39: "RIGHT", // right arrow + 88: "CIRCLE", // x key + 90: "X", // z key + 68: "TRIANGLE", // d key + 69: "L2", // e key + 32: "SPACE", + }; + return keyCodeAssocs[keyCode as keyof typeof keyCodeAssocs]; +}; diff --git a/src/scenes/GateScene.tsx b/src/scenes/GateScene.tsx index 26e4d1a..99d5499 100644 --- a/src/scenes/GateScene.tsx +++ b/src/scenes/GateScene.tsx @@ -4,6 +4,7 @@ import { OrbitControls } from "@react-three/drei"; import GateHUD from "../components/GateScene/GateHUD"; import GateMiddleObject from "../components/GateScene/GateMiddleObject"; import { useGateStore } from "../store"; +import GateSceneManager from "../core/StateManagers/GateSceneManager"; const GateScene = () => { const gateLvl = useGateStore((state) => state.gateLvl); @@ -22,6 +23,7 @@ const GateScene = () => { + ); }; diff --git a/src/scenes/MediaScene.tsx b/src/scenes/MediaScene.tsx index 783d58d..c618134 100644 --- a/src/scenes/MediaScene.tsx +++ b/src/scenes/MediaScene.tsx @@ -19,6 +19,7 @@ import site_a from "../resources/site_a.json"; import { SiteType } from "../components/MainScene/SyncedComponents/Site"; import MediaYellowTextAnimator from "../components/TextRenderer/MediaYellowTextAnimator"; import site_b from "../resources/site_b.json"; +import MediaSceneEventManager from "../core/StateManagers/MediaSceneEventManager"; const MediaScene = () => { const currentScene = useSceneStore((state) => state.currentScene); @@ -91,6 +92,7 @@ const MediaScene = () => { <> )} + ); }; diff --git a/src/scenes/SSknScene.tsx b/src/scenes/SSknScene.tsx index ca0850f..bc012eb 100644 --- a/src/scenes/SSknScene.tsx +++ b/src/scenes/SSknScene.tsx @@ -3,6 +3,7 @@ import SSknIcon from "../components/SSknScene/SSknIcon"; import SSknBackground from "../components/SSknScene/SSknBackground"; import SSknHUD from "../components/SSknScene/SSknHUD"; import { useMediaStore, useSSknStore } from "../store"; +import SSknSceneManager from "../core/StateManagers/SSknSceneManager"; const SSknScene = () => { const ssknComponentMatrixIdx = useSSknStore( @@ -21,6 +22,7 @@ const SSknScene = () => { + ); };