From 7db4906db1c85df63181c537a31307283b9a2d10 Mon Sep 17 00:00:00 2001 From: ad044 Date: Wed, 2 Dec 2020 20:50:12 +0400 Subject: [PATCH] more progress on the pause animation --- src/components/MainScene/Pause.tsx | 294 ++++++++++-------- src/components/MainScene/PauseSquare.tsx | 86 +++++ src/components/TextRenderer/BigLetter.tsx | 4 +- .../TextRenderer/StaticBigLetter.tsx | 123 ++++++++ .../TextRenderer/YellowTextRenderer.tsx | 4 +- src/core/StateManagers/EventManager.tsx | 6 + .../StateManagers/PauseComponentManager.tsx | 42 +++ src/core/mainSceneEventHandler.ts | 16 + src/store.ts | 15 +- 9 files changed, 455 insertions(+), 135 deletions(-) create mode 100644 src/components/MainScene/PauseSquare.tsx create mode 100644 src/components/TextRenderer/StaticBigLetter.tsx create mode 100644 src/core/StateManagers/PauseComponentManager.tsx diff --git a/src/components/MainScene/Pause.tsx b/src/components/MainScene/Pause.tsx index 446f1e5..8bbe9a9 100644 --- a/src/components/MainScene/Pause.tsx +++ b/src/components/MainScene/Pause.tsx @@ -1,11 +1,16 @@ -import React, { useCallback, useMemo, useRef, useState } from "react"; -import pauseGrayBoxes from "../../static/sprite/pause_gray_boxes.png"; +import React, { useCallback, useMemo } from "react"; import * as THREE from "three"; -import { useFrame, useLoader } from "react-three-fiber"; -import BigLetter from "../TextRenderer/BigLetter"; +import PauseSquare from "./PauseSquare"; +import StaticBigLetter from "../TextRenderer/StaticBigLetter"; +import { usePauseStore } from "../../store"; const Pause = () => { - const grayBoxesTex = useLoader(THREE.TextureLoader, pauseGrayBoxes); + const componentMatrixIdx = usePauseStore((state) => state.componentMatrixIdx); + const activeComponent = usePauseStore( + useCallback((state) => state.componentMatrix[componentMatrixIdx], [ + componentMatrixIdx, + ]) + ); const generateSqaureGeom = useCallback((row: number, square: number) => { const geometry = new THREE.PlaneBufferGeometry(); @@ -34,147 +39,178 @@ const Pause = () => { {[0, 1, 2, 3, 2, 1, 0].map((row: number, rowIdx: number) => [0, 1, 2, 3, 4, 5, 6].map((col: number) => { - if (rowIdx === 5 && col > 0) { + if (rowIdx === 5 && col > 0 && col < 5) { return col === 1 ? ( - <> - - - - ) - - ) : ( - 3 ? -0.25 : 0.25, rowIdx <= 3 ? -0.25 : 0.25, 0]} + - 3 && rowIdx <= 3) || (col <= 3 && rowIdx > 3) - ? THREE.FrontSide - : THREE.BackSide - } - /> - + /> + ) : ( + ); - } else if (rowIdx === 4 && col === 4) { - return ( - <> - - - - + } else if (rowIdx === 4 && col > 4 && col < 7) { + return col === 5 ? ( + + ) : ( + ); - } else if (rowIdx === 3 && col === 3) { - return ( - <> - - - - + } else if (rowIdx === 3 && col > 2 && col < 7) { + return col === 3 ? ( + + ) : ( + + ); + } else if (rowIdx === 1 && col > 0 && col < 5) { + return col === 1 ? ( + + ) : ( + + ); + } else if (rowIdx === 0 && col > 4 && col < 7) { + return col === 5 ? ( + + ) : ( + ); } else { return ( - 3 ? -0.25 : 0.25, rowIdx <= 3 ? -0.25 : 0.25, 0]} + rowIdx={rowIdx} + colIdx={col} key={col} - > - 3 && rowIdx <= 3) || (col <= 3 && rowIdx > 3) - ? THREE.FrontSide - : THREE.BackSide - } - /> - + active={true} + /> ); } }) )} - {/*{"Load".split("").map((letter, idx) => (*/} - {/* */} - {/* 0 ? "yellow" : "orange"}*/} - {/* letter={letter}*/} - {/* letterIdx={idx}*/} - {/* yellowTextOffsetXCoeff={0}*/} - {/* key={idx}*/} - {/* />*/} - {/* */} - {/*))}*/} + {"Load".split("").map((letter, idx) => ( + 0 ? "yellow" : "orange"} + letter={letter} + letterIdx={idx} + key={idx} + position={[0.35 + idx / 2.8, 1.8, 0]} + scale={[0.25, 0.25, 0.25]} + active={activeComponent === "load"} + /> + ))} - {/*{"About".split("").map((letter, idx) => (*/} - {/* */} - {/* 0 ? "yellow" : "orange"}*/} - {/* letter={letter}*/} - {/* letterIdx={idx}*/} - {/* yellowTextOffsetXCoeff={0}*/} - {/* key={idx}*/} - {/* />*/} - {/* */} - {/*))}*/} + {"About".split("").map((letter, idx) => ( + 0 ? "yellow" : "orange"} + letter={letter} + letterIdx={idx} + position={[1.78 + idx / 2.8, 1.43, 0]} + scale={[0.25, 0.25, 0]} + active={activeComponent === "about"} + key={idx} + /> + ))} - {/*{"Change".split("").map((letter, idx) => (*/} - {/* */} - {/* 0 ? "yellow" : "orange"}*/} - {/* letter={letter}*/} - {/* letterIdx={idx}*/} - {/* yellowTextOffsetXCoeff={0}*/} - {/* key={idx}*/} - {/* />*/} - {/* */} - {/*))}*/} + {"Change".split("").map((letter, idx) => ( + 0 ? "yellow" : "orange"} + letter={letter} + letterIdx={idx} + position={[1.05 + idx / 2.8, 1.07, 0]} + scale={[0.25, 0.25, 0]} + active={activeComponent === "change"} + key={idx} + /> + ))} - {/*{"Save".split("").map((letter, idx) => (*/} - {/* */} - {/* 0 ? "yellow" : "orange"}*/} - {/* letter={letter}*/} - {/* letterIdx={idx}*/} - {/* yellowTextOffsetXCoeff={0}*/} - {/* key={idx}*/} - {/* />*/} - {/* */} - {/*))}*/} + {"Save".split("").map((letter, idx) => ( + 0 ? "yellow" : "orange"} + letter={letter} + letterIdx={idx} + position={[0.35 + idx / 2.8, 0.35, 0]} + scale={[0.25, 0.25, 0]} + active={activeComponent === "save"} + key={idx} + /> + ))} - {/*{"Exit".split("").map((letter, idx) => (*/} - {/* */} - {/* 0 ? "yellow" : "orange"}*/} - {/* letter={letter}*/} - {/* letterIdx={idx}*/} - {/* yellowTextOffsetXCoeff={0}*/} - {/* key={idx}*/} - {/* />*/} - {/* */} - {/*))}*/} + {"Exit".split("").map((letter, idx) => ( + 0 ? "yellow" : "orange"} + letter={letter} + letterIdx={idx} + position={[1.78 + idx / 2.8, 0, 0]} + scale={[0.25, 0.25, 0]} + key={idx} + active={activeComponent === "exit"} + /> + ))} ); }; diff --git a/src/components/MainScene/PauseSquare.tsx b/src/components/MainScene/PauseSquare.tsx new file mode 100644 index 0000000..d5d7a7b --- /dev/null +++ b/src/components/MainScene/PauseSquare.tsx @@ -0,0 +1,86 @@ +import React, { useEffect, useMemo, useState } from "react"; +import * as THREE from "three"; +import { useLoader } from "react-three-fiber"; +import pauseGrayBoxes from "../../static/sprite/pause_gray_boxes.png"; +import { a, useSpring } from "@react-spring/three"; + +type PauseSquareProps = { + colIdx: number; + rowIdx: number; + geometry: THREE.PlaneBufferGeometry; + active: boolean; +}; + +const PauseSquare = (props: PauseSquareProps) => { + const grayBoxesTex = useLoader(THREE.TextureLoader, pauseGrayBoxes); + + const [intro, setIntro] = useState(true); + const [introAnimToggle, setIntroAnimToggle] = useState(false); + + const { introToggle } = useSpring({ + introToggle: Number(introAnimToggle), + config: { duration: 200 }, + }); + + const { toggle } = useSpring({ + toggle: Number(props.active), + config: { duration: 200 }, + }); + + const rotX = toggle.to([0, 1], [-Math.PI, 0]); + const rotY = toggle.to([0, 1], [Math.PI / 2, 0]); + + const introRotX = introToggle.to([0, 1], [0, 2 * Math.PI]); + const introRotY = introToggle.to([0, 1], [0, 2 * Math.PI]); + + useEffect(() => { + setTimeout(() => { + setIntroAnimToggle(true); + }, (props.rowIdx + props.colIdx) * 100); + + setTimeout(() => { + setIntro(false); + }, 5000); + }, [props.colIdx, props.rowIdx]); + + const side = useMemo(() => { + if (intro) return THREE.DoubleSide; + else { + if ( + (props.colIdx > 3 && props.rowIdx <= 3) || + (props.colIdx <= 3 && props.rowIdx > 3) + ) { + return THREE.FrontSide; + } else { + return THREE.BackSide; + } + } + }, [intro, props.colIdx, props.rowIdx]); + + return ( + 3 ? -0.25 : 0.25, + props.rowIdx <= 3 ? -0.25 : 0.25, + 0, + ]} + rotation-x={intro ? introRotX : rotX} + rotation-y={intro ? introRotY : rotY} + > + 3 && props.rowIdx <= 3) || + (props.colIdx <= 3 && props.rowIdx > 3) + ? THREE.FrontSide + : THREE.BackSide + } + /> + + ); +}; + +export default PauseSquare; diff --git a/src/components/TextRenderer/BigLetter.tsx b/src/components/TextRenderer/BigLetter.tsx index 713bc80..a2823c4 100644 --- a/src/components/TextRenderer/BigLetter.tsx +++ b/src/components/TextRenderer/BigLetter.tsx @@ -11,7 +11,7 @@ const BigLetter = (props: { color: string; letter: string; letterIdx: number; - yellowTextOffsetXCoeff: number; + xOffsetCoeff: number; }) => { const colorToTexture = (color: string) => { const colorTexture = { @@ -93,7 +93,7 @@ const BigLetter = (props: { letterOffsetXCoeff: props.letterIdx + 0.3 + - (props.letterIdx + 0.3) * props.yellowTextOffsetXCoeff, + (props.letterIdx + 0.3) * props.xOffsetCoeff, config: { duration: 200 }, }); diff --git a/src/components/TextRenderer/StaticBigLetter.tsx b/src/components/TextRenderer/StaticBigLetter.tsx new file mode 100644 index 0000000..a6760ab --- /dev/null +++ b/src/components/TextRenderer/StaticBigLetter.tsx @@ -0,0 +1,123 @@ +import orangeFont from "../../static/sprite/orange_font_texture.png"; +import yellowFont from "../../static/sprite/yellow_font_texture.png"; +import whiteFont from "../../static/sprite/white_and_green_texture.png"; +import * as THREE from "three"; +import { useLoader } from "react-three-fiber"; +import orange_font_json from "../../resources/font_data/big_font.json"; +import { a, Interpolation, SpringValue, useSpring } from "@react-spring/three"; +import React, { useMemo } from "react"; + +const StaticBigLetter = (props: { + color: string; + letter: string; + letterIdx: number; + position: number[]; + scale: number[]; + active: boolean; +}) => { + const { toggle } = useSpring({ + toggle: Number(props.active), + config: { duration: 200 }, + }); + + const rotX = toggle.to([0, 1], [-Math.PI, 0]); + const rotY = toggle.to([0, 1], [Math.PI / 2, 0]); + + const colorToTexture = (color: string) => { + const colorTexture = { + orange: orangeFont, + yellow: yellowFont, + white: whiteFont, + }; + return colorTexture[color as keyof typeof colorTexture]; + }; + + // first letter in big font is always orange in this case so make it orange if so. else, + // run through the function. + const color = + props.letterIdx === 0 ? orangeFont : colorToTexture(props.color); + + const colorTexture: THREE.Texture = useLoader(THREE.TextureLoader, color); + + // i have yet to figure out a genrealizable way of + // calculating the y offset, this shit will do for now + // also, we dont have all the lines since i dont need them yet. + // also, baseline offsets dont work properly since i dont need them yet either + // should be trivial to calculate though, im just lazy + const getLineNum = (letter: string) => { + const lineOne = "ABCDEFGHIJKLMNOPQ"; + const lineTwo = "RSTUVWXYZ01234567"; + const lineThree = "89abcdefghijklmnopqrs"; + + if (letter === " ") return 5; + + if (lineOne.includes(letter)) { + return 1; + } else if (lineTwo.includes(letter)) { + return 2; + } else if (lineThree.includes(letter)) { + return 3; + } else { + return 4; + } + }; + + const lineYOffsets = useMemo( + () => ({ + 1: 0.884, + 2: 0.765, + 3: 0.648, + 4: 0.47, + 5: 1, + }), + [] + ); + + const letterData = + orange_font_json.glyphs[ + props.letter as keyof typeof orange_font_json.glyphs + ]; + + const geom = useMemo(() => { + const geometry = new THREE.PlaneBufferGeometry(); + + const uvAttribute = geometry.attributes.uv; + + for (let i = 0; i < uvAttribute.count; i++) { + let u = uvAttribute.getX(i); + let v = uvAttribute.getY(i); + + u = (u * letterData[2]) / 256 + letterData[0] / 256; + + v = + (v * letterData[3]) / 136 + + lineYOffsets[getLineNum(props.letter)] - + letterData[4] / 136; + + uvAttribute.setXY(i, u, v); + } + return geometry; + }, [letterData, lineYOffsets, props.letter]); + + return ( + + + + ); +}; + +export default StaticBigLetter; diff --git a/src/components/TextRenderer/YellowTextRenderer.tsx b/src/components/TextRenderer/YellowTextRenderer.tsx index 292d461..e5a18ea 100644 --- a/src/components/TextRenderer/YellowTextRenderer.tsx +++ b/src/components/TextRenderer/YellowTextRenderer.tsx @@ -52,7 +52,7 @@ const YellowTextRenderer = (props: { visible?: boolean }) => { > { > { const keyCodeAssocs = { @@ -62,6 +64,7 @@ const EventManager = () => { const levelSelectionIdx = useLevelSelectionStore( (state) => state.selectedLevelIdx ); + const pauseMatrixIdx = usePauseStore((state) => state.componentMatrixIdx); // media scene const mediaComponentMatrixIndices = useMediaStore( @@ -142,6 +145,7 @@ const EventManager = () => { nodeMatrixIndices: nodeMatrixIndices, activeLevel: activeLevel, levelSelectionIdx: levelSelectionIdx, + pauseMatrixIdx: pauseMatrixIdx, }); break; case "media": @@ -189,6 +193,7 @@ const EventManager = () => { levelSelectionIdx, mainSubscene, nodeMatrixIndices, + pauseMatrixIdx, rightSideComponentIdx, siteTransformState, wordPosStateIdx, @@ -221,6 +226,7 @@ const EventManager = () => { + ); }; diff --git a/src/core/StateManagers/PauseComponentManager.tsx b/src/core/StateManagers/PauseComponentManager.tsx new file mode 100644 index 0000000..22176e1 --- /dev/null +++ b/src/core/StateManagers/PauseComponentManager.tsx @@ -0,0 +1,42 @@ +import { useCallback, useEffect } from "react"; +import { StateManagerProps } from "./EventManager"; +import { usePauseStore } from "../../store"; + +const PauseComponentManager = (props: StateManagerProps) => { + const setComponentMatrixIdx = usePauseStore( + (state) => state.setComponentMatrixIdx + ); + + const dispatchObject = useCallback( + (event: string, newComponentMatrixIdx: number) => { + switch (event) { + case "pause_up": + case "pause_down": + return { + action: setComponentMatrixIdx, + value: newComponentMatrixIdx, + }; + } + }, + [setComponentMatrixIdx] + ); + + useEffect(() => { + if (props.eventState) { + const eventAction = props.eventState.event; + const newComponentMatrixIdx = props.eventState.newPauseMatrixIdx; + + const dispatchedObject = dispatchObject( + eventAction, + newComponentMatrixIdx + ); + + if (dispatchedObject) { + dispatchedObject.action(dispatchedObject.value as never); + } + } + }, [dispatchObject, props.eventState]); + return null; +}; + +export default PauseComponentManager; diff --git a/src/core/mainSceneEventHandler.ts b/src/core/mainSceneEventHandler.ts index 0f69ab7..f6cd56a 100644 --- a/src/core/mainSceneEventHandler.ts +++ b/src/core/mainSceneEventHandler.ts @@ -23,6 +23,7 @@ const handleMainSceneEvent = (gameContext: any) => { const keyPress = gameContext.keyPress; const subscene = gameContext.mainSubscene; const levelSelectionIdx = gameContext.levelSelectionIdx; + const pauseMatrixIdx = gameContext.pauseMatrixIdx; const nodeColIdx = gameContext.nodeMatrixIndices.colIdx; const nodeRowIdx = gameContext.nodeMatrixIndices.rowIdx; @@ -198,6 +199,21 @@ const handleMainSceneEvent = (gameContext: any) => { }; } } + } else if (subscene === "pause") { + switch (keyPress) { + case "UP": + if (pauseMatrixIdx - 1 < 0) break; + return { + event: "pause_up", + newPauseMatrixIdx: pauseMatrixIdx - 1, + }; + case "DOWN": + if (pauseMatrixIdx + 1 > 4) break; + return { + event: "pause_down", + newPauseMatrixIdx: pauseMatrixIdx + 1, + }; + } } }; diff --git a/src/store.ts b/src/store.ts index df409e2..07eb155 100644 --- a/src/store.ts +++ b/src/store.ts @@ -3,6 +3,12 @@ import { combine } from "zustand/middleware"; import * as THREE from "three"; import authorize_user_letters from "./resources/authorize_user_letters.json"; +type PauseState = { + componentMatrix: string[]; + componentMatrixIdx: number; + setComponentMatrixIdx: (to: number) => void; +}; + type LevelSelectionState = { availableLevels: number[]; selectedLevelIdx: number; @@ -397,7 +403,7 @@ export const useAuthorizeUserStore = create((set) => ({ })); export const useMainSceneStore = create((set) => ({ - subscene: "site", + subscene: "pause", setSubscene: (to) => set(() => ({ subscene: to })), })); @@ -470,4 +476,9 @@ export const useLevelSelectionStore = create((set) => ({ })), })); -export const usePauseStore = create((set) => ({})); +export const usePauseStore = create((set) => ({ + componentMatrix: ["load", "about", "change", "save", "exit"], + componentMatrixIdx: 2, + setComponentMatrixIdx: (to: number) => + set(() => ({ componentMatrixIdx: to })), +}));