From abed73e236f51afa9c534e0dbfe032aa02d80d80 Mon Sep 17 00:00:00 2001 From: ad044 Date: Sun, 6 Dec 2020 18:02:09 +0400 Subject: [PATCH] rewrote starfield --- src/components/MainScene/Lain.tsx | 2 +- .../MainScene/{ => PauseSubscene}/Pause.tsx | 59 +-- .../{ => PauseSubscene}/PauseSquare.tsx | 4 +- src/components/MainScene/Starfield.tsx | 346 ------------------ src/components/MainScene/Starfield/Star.tsx | 80 ++++ .../MainScene/Starfield/Starfield.tsx | 57 +++ src/core/StateManagers/SubsceneManager.tsx | 12 +- src/scenes/MainScene.tsx | 8 +- 8 files changed, 184 insertions(+), 384 deletions(-) rename src/components/MainScene/{ => PauseSubscene}/Pause.tsx (89%) rename src/components/MainScene/{ => PauseSubscene}/PauseSquare.tsx (96%) delete mode 100644 src/components/MainScene/Starfield.tsx create mode 100644 src/components/MainScene/Starfield/Star.tsx create mode 100644 src/components/MainScene/Starfield/Starfield.tsx diff --git a/src/components/MainScene/Lain.tsx b/src/components/MainScene/Lain.tsx index 0d1eb40..2b30c6e 100644 --- a/src/components/MainScene/Lain.tsx +++ b/src/components/MainScene/Lain.tsx @@ -9,7 +9,7 @@ import moveRightSpriteSheet from "../../static/sprite/move_right.png"; import standingSpriteSheet from "../../static/sprite/standing.png"; import introSpriteSheet from "../../static/sprite/intro.png"; import throwNodeSpriteSheet from "../../static/sprite/throw_node.png"; -import { useLainStore } from "../../store"; +import { useLainStore, useMainSceneStore } from "../../store"; type LainConstructorProps = { sprite: string; diff --git a/src/components/MainScene/Pause.tsx b/src/components/MainScene/PauseSubscene/Pause.tsx similarity index 89% rename from src/components/MainScene/Pause.tsx rename to src/components/MainScene/PauseSubscene/Pause.tsx index 0e2f1c7..473b23b 100644 --- a/src/components/MainScene/Pause.tsx +++ b/src/components/MainScene/PauseSubscene/Pause.tsx @@ -1,11 +1,12 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import * as THREE from "three"; import PauseSquare from "./PauseSquare"; -import StaticBigLetter from "../TextRenderer/StaticBigLetter"; -import { usePauseStore } from "../../store"; +import StaticBigLetter from "../../TextRenderer/StaticBigLetter"; +import { usePauseStore } from "../../../store"; import { useLoader } from "react-three-fiber"; const Pause = (props: { visible: boolean }) => { + const exit = usePauseStore((state) => state.exitAnimation); const [showActiveComponent, setShowActiveComponent] = useState(false); const [animation, setAnimation] = useState(false); const [intro, setIntro] = useState(true); @@ -77,7 +78,7 @@ const Pause = (props: { visible: boolean }) => { [0, 1, 2, 3, 4, 5, 6].map((col: number) => { if (rowIdx === 5 && col > 0 && col < 5) { return col === 1 ? ( - <> + { position={[0.35, 1.8, 0]} scale={[0.25, 0.25, 0.25]} active={!(activeComponent === "load")} - key={col} + key={"whiteL"} rowIdx={rowIdx} colIdx={col} intro={intro} @@ -94,24 +95,24 @@ const Pause = (props: { visible: boolean }) => { geometry={squareGeoms[row][col]} rowIdx={rowIdx} colIdx={col} - key={col} + key={"whiteLsquare"} shouldDisappear={true} intro={intro} /> - + ) : ( ); } else if (rowIdx === 4 && col > 4 && col < 7) { return col === 5 ? ( - <> + { position={[1.78, 1.43, 0]} scale={[0.25, 0.25, 0]} active={!(activeComponent === "about")} - key={col} + key={"whiteA"} rowIdx={rowIdx} colIdx={col} intro={intro} @@ -128,24 +129,24 @@ const Pause = (props: { visible: boolean }) => { geometry={squareGeoms[row][col]} rowIdx={rowIdx} colIdx={col} - key={col} + key={"whiteAsquare"} shouldDisappear={true} intro={intro} /> - + ) : ( ); } else if (rowIdx === 3 && col > 2 && col < 7) { return col === 3 ? ( - <> + { position={[1.05, 1.07, 0]} scale={[0.25, 0.25, 0]} active={!(activeComponent === "change")} - key={col} + key={"whiteC"} rowIdx={rowIdx} colIdx={col} intro={intro} @@ -162,24 +163,24 @@ const Pause = (props: { visible: boolean }) => { geometry={squareGeoms[row][col]} rowIdx={rowIdx} colIdx={col} - key={col} + key={"whiteCsquare"} shouldDisappear={true} intro={intro} /> - + ) : ( ); } else if (rowIdx === 1 && col > 0 && col < 5) { return col === 1 ? ( - <> + { position={[0.35, 0.35, 0]} scale={[0.25, 0.25, 0]} active={!(activeComponent === "save")} - key={col} + key={"whiteS"} rowIdx={rowIdx} colIdx={col} intro={intro} @@ -196,24 +197,24 @@ const Pause = (props: { visible: boolean }) => { geometry={squareGeoms[row][col]} rowIdx={rowIdx} colIdx={col} - key={col} + key={"whiteSsquare"} shouldDisappear={true} intro={intro} /> - + ) : ( ); } else if (rowIdx === 0 && col > 4 && col < 7) { return col === 5 ? ( - <> + { position={[1.78, 0, 0]} scale={[0.25, 0.25, 0]} active={!(activeComponent === "exit")} - key={col} + key={"whiteE"} rowIdx={1} colIdx={col} intro={intro} @@ -230,18 +231,18 @@ const Pause = (props: { visible: boolean }) => { geometry={squareGeoms[row][col]} rowIdx={rowIdx} colIdx={col} - key={col} + key={"whiteEsquare"} shouldDisappear={true} intro={intro} /> - + ) : ( ); @@ -251,7 +252,7 @@ const Pause = (props: { visible: boolean }) => { geometry={squareGeoms[row][col]} rowIdx={rowIdx} colIdx={col} - key={col} + key={`${rowIdx}${col}r`} active={true} intro={intro} /> @@ -319,7 +320,7 @@ const Pause = (props: { visible: boolean }) => { /> ))} - + []>, - number[][] -][]; - -type StarfieldObjectData = { - starPoses: number[][]; - ref: React.MutableRefObject[]>; - rotation: number[]; - positionSpecifier: number[]; - uniform?: - | { color1: { value: THREE.Color }; color2: { value: THREE.Color } } - | undefined; -}; - -type IntroStarfieldObjectData = { - starPoses: number[][]; - ref: React.MutableRefObject[]>; - uniform?: - | { color1: { value: THREE.Color }; color2: { value: THREE.Color } } - | undefined; -}; - -const Starfield = memo(() => { - const introStarfieldGroupRef = useRef(); - - const introStarfieldVisible = useStarfieldStore( - (state) => state.introStarfieldVisible - ); - const mainStarfieldVisible = useStarfieldStore( - (state) => state.mainStarfieldVisible - ); - - const mainStarfieldBoostVal = useStarfieldStore( - (state) => state.mainStarfieldBoostVal - ); - - const starfieldState = useSpring({ - starfieldBoostVal: mainStarfieldBoostVal, - config: { duration: 1200 }, - }); - - const vertexShader = ` - varying vec2 vUv; - - void main() { - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - } - `; - - const fragmentShader = ` - uniform vec3 color1; - uniform vec3 color2; - uniform float alpha; - - varying vec2 vUv; - - void main() { - float alpha = smoothstep(0.0, 1.0, vUv.y); - float colorMix = smoothstep(1.0, 2.0, 1.8); - - gl_FragColor = vec4(mix(color1, color2, colorMix), alpha); - } - `; - - const LCG = (a: number, c: number, m: number, s: number) => () => - (s = (s * a + c) % m); - - const lcgInstance = LCG(1664525, 1013904223, 2 ** 32, 2); - - const uniformConstructor = (col: string) => { - return { - color1: { - value: new THREE.Color("white"), - }, - color2: { - value: new THREE.Color(col), - }, - }; - }; - - const [blueUniforms, cyanUniforms, whiteUniforms] = [ - "blue", - "cyan", - "gray", - // eslint-disable-next-line react-hooks/rules-of-hooks - ].map((color: string) => useMemo(() => uniformConstructor(color), [color])); - - const [ - posesBlueFromRight, - posesBlueFromLeft, - posesCyanFromRight, - posesCyanFromLeft, - posesWhiteFromRight, - posesWhiteFromLeft, - ] = [5, 5, 5, 5, 5, 5].map((x) => - Array.from({ length: x }, () => [ - lcgInstance() / 1000000000, - lcgInstance() / 1000000000 - 1, - lcgInstance() / 1000000000, - ]) - ); - - const [ - blueFromRightRef, - blueFromLeftRef, - cyanFromRightRef, - cyanFromLeftRef, - whiteFromRightRef, - whiteFromLeftRef, - ] = [ - posesBlueFromRight, - posesBlueFromLeft, - posesCyanFromRight, - posesCyanFromLeft, - posesWhiteFromRight, - posesWhiteFromLeft, - ].map((poses) => - // eslint-disable-next-line react-hooks/rules-of-hooks - useRef[]>( - poses.map(() => createRef()) - ) - ); - - const [introPosesBlue, introPosesCyan, introPosesWhite] = [ - 80, - 80, - 60, - ].map((x) => - Array.from({ length: x }, () => [ - lcgInstance() / 1000000050, - lcgInstance() / 100000099, - lcgInstance() / 1000000050, - ]) - ); - - const [introBlueRef, introCyanRef, introWhiteRef] = [ - introPosesBlue, - introPosesCyan, - introPosesWhite, - ].map((poses) => - // eslint-disable-next-line react-hooks/rules-of-hooks - useRef[]>( - poses.map(() => createRef()) - ) - ); - - const fromRightStarRefsAndInitialPoses: StarRefsAndInitialPoses = [ - [blueFromRightRef, posesBlueFromRight], - [cyanFromRightRef, posesCyanFromRight], - [whiteFromRightRef, posesWhiteFromRight], - ]; - - const fromLeftStarRefsAndInitialPoses: StarRefsAndInitialPoses = [ - [blueFromLeftRef, posesBlueFromLeft], - [cyanFromLeftRef, posesCyanFromLeft], - [whiteFromLeftRef, posesWhiteFromLeft], - ]; - - const starSpeeds = Array.from( - { length: 60 }, - () => lcgInstance() / 100000000000 + 0.03 - ); - - useFrame(() => { - if (introStarfieldVisible) { - introStarfieldGroupRef.current!.position.y += 0.2; - } - if (mainStarfieldVisible) { - // planes (stars) coming from right move to positive X and negative Z direction - fromRightStarRefsAndInitialPoses.forEach((el) => { - el[0].current.forEach( - (posRef: RefObject, idx: number) => { - if (posRef.current!.position.x < -1) { - posRef.current!.position.x = el[1][idx][0] + 6; - posRef.current!.position.z = el[1][idx][2] - 2.5; - } - posRef.current!.position.x -= - starSpeeds[idx] + starfieldState.starfieldBoostVal.get(); - posRef.current!.position.z += - 0.035 + starfieldState.starfieldBoostVal.get() * 0.5; - } - ); - }); - // the ones that are coming from left move to negative X and Z - fromLeftStarRefsAndInitialPoses.forEach((el) => { - el[0].current.forEach( - (posRef: RefObject, idx: number) => { - if (posRef.current!.position.x > 3) { - posRef.current!.position.x = el[1][idx][0] - 9; - posRef.current!.position.z = el[1][idx][2] - 0.5; - } else { - posRef.current!.position.x += - starSpeeds[idx] + starfieldState.starfieldBoostVal.get(); - posRef.current!.position.z += - 0.015 + starfieldState.starfieldBoostVal.get() * 0.5; - } - } - ); - }); - } - }); - - const mainStarfieldObjects = [ - { - starPoses: posesBlueFromRight, - ref: blueFromRightRef, - rotation: [1.7, 0, 1], - positionSpecifier: [6, 0, -2.5], - uniform: blueUniforms, - }, - { - starPoses: posesBlueFromLeft, - ref: blueFromLeftRef, - rotation: [1.7, 0, -1.2], - positionSpecifier: [-2.4, -0.5, 2], - uniform: blueUniforms, - }, - { - starPoses: posesCyanFromRight, - ref: cyanFromRightRef, - rotation: [1.7, 0, 1], - positionSpecifier: [6, 0, -2.5], - uniform: cyanUniforms, - }, - { - starPoses: posesCyanFromLeft, - ref: cyanFromLeftRef, - rotation: [1.7, 0, -1.2], - positionSpecifier: [-1.3, 0, 2.5], - uniform: cyanUniforms, - }, - { - starPoses: posesWhiteFromLeft, - ref: whiteFromLeftRef, - rotation: [1.7, 0, -1.2], - positionSpecifier: [-1.3, 0.5, 2.3], - uniform: whiteUniforms, - }, - { - starPoses: posesWhiteFromRight, - ref: whiteFromRightRef, - rotation: [1.7, 0, 1], - positionSpecifier: [-1.3, 0.5, -2.5], - uniform: whiteUniforms, - }, - ]; - - const introStarfieldObjects = [ - { - starPoses: introPosesBlue, - ref: introBlueRef, - uniform: blueUniforms, - }, - { - starPoses: introPosesCyan, - ref: introCyanRef, - uniform: cyanUniforms, - }, - { - starPoses: introPosesWhite, - ref: introWhiteRef, - uniform: whiteUniforms, - }, - ]; - - return ( - <> - - {introStarfieldObjects.map((obj: IntroStarfieldObjectData) => - obj.starPoses.map((pos: number[], idx: number) => { - return ( - - - - - ); - }) - )} - - - {mainStarfieldObjects.map((obj: StarfieldObjectData) => - obj.starPoses.map((pos: number[], idx: number) => { - return ( - - - - - ); - }) - )} - - - ); -}); - -export default Starfield; diff --git a/src/components/MainScene/Starfield/Star.tsx b/src/components/MainScene/Starfield/Star.tsx new file mode 100644 index 0000000..862ca8b --- /dev/null +++ b/src/components/MainScene/Starfield/Star.tsx @@ -0,0 +1,80 @@ +import React, { useRef } from "react"; +import { a } from "@react-spring/three"; +import * as THREE from "three"; +import { useFrame } from "react-three-fiber"; + +type StarProps = { + position: number[]; + color: string; +}; + +const Star = (props: StarProps) => { + const uniformConstructor = (col: string) => { + return { + color1: { + value: new THREE.Color("white"), + }, + color2: { + value: new THREE.Color(col), + }, + }; + }; + + const vertexShader = ` + varying vec2 vUv; + + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + } + `; + + const fragmentShader = ` + uniform vec3 color1; + uniform vec3 color2; + uniform float alpha; + + varying vec2 vUv; + + void main() { + float alpha = smoothstep(0.0, 1.0, vUv.y); + float colorMix = smoothstep(1.0, 2.0, 1.8); + + gl_FragColor = vec4(mix(color1, color2, colorMix), alpha) * 0.8; + } + `; + + const starRef = useRef(); + + const amp = useRef(Math.random() / 10); + + useFrame(() => { + if (starRef.current) { + if (starRef.current.position.y > 4) { + starRef.current.position.y = props.position[1]; + } + starRef.current.position.y += (0.01 + amp.current); + } + }); + + return ( + + + + + ); +}; + +export default Star; diff --git a/src/components/MainScene/Starfield/Starfield.tsx b/src/components/MainScene/Starfield/Starfield.tsx new file mode 100644 index 0000000..38ef618 --- /dev/null +++ b/src/components/MainScene/Starfield/Starfield.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import Star from "./Star"; + +type StarfieldProps = { + visible: boolean; +} + +const Starfield = (props: StarfieldProps) => { + const LCG = (a: number, c: number, m: number, s: number) => () => + (s = (s * a + c) % m); + + const lcgInstance = LCG(1664525, 1013904223, 2 ** 32, 2); + + const [ + posesBlueFromRight, + posesBlueFromLeft, + posesCyanFromRight, + posesCyanFromLeft, + posesWhiteFromRight, + posesWhiteFromLeft, + ] = [5, 5, 5, 5, 5, 5].map((x) => + Array.from({ length: x }, () => [ + lcgInstance() / 1000000000, + lcgInstance() / 10000000000 - 10, + lcgInstance() / 1000000000, + ]) + ); + + return ( + + + {posesBlueFromLeft.map((poses, idx) => ( + + ))} + {posesWhiteFromLeft.map((poses, idx) => ( + + ))} + {posesCyanFromLeft.map((poses, idx) => ( + + ))} + + + {posesBlueFromRight.map((poses, idx) => ( + + ))} + {posesWhiteFromRight.map((poses, idx) => ( + + ))} + {posesCyanFromRight.map((poses, idx) => ( + + ))} + + + ); +}; + +export default Starfield; diff --git a/src/core/StateManagers/SubsceneManager.tsx b/src/core/StateManagers/SubsceneManager.tsx index b33fdb0..8c39323 100644 --- a/src/core/StateManagers/SubsceneManager.tsx +++ b/src/core/StateManagers/SubsceneManager.tsx @@ -15,35 +15,41 @@ const SubsceneManager = (props: StateManagerProps) => { return { action: setMainSubscene, value: "site", + delay: 0, }; case "toggle_level_selection": return { action: setMainSubscene, value: "level_selection", + delay: 0, }; case "toggle_pause": return { action: setMainSubscene, value: "pause", + delay: 0, }; case "pause_exit_select": return { action: setMainSubscene, value: "site", + delay: 1800, }; case "authorize_user_back": case "load_data_no_select": return { action: setBootSubscene, value: "main_menu", + delay: 0, }; case "authorize_user_select": return { action: setBootSubscene, value: "authorize_user", + delay: 0, }; case "load_data_select": - return { action: setBootSubscene, value: "load_data" }; + return { action: setBootSubscene, value: "load_data", delay: 0 }; } }, [setBootSubscene, setMainSubscene] @@ -56,7 +62,9 @@ const SubsceneManager = (props: StateManagerProps) => { const dispatchedObject = dispatchObject(eventAction); if (dispatchedObject) { - dispatchedObject.action(dispatchedObject.value); + setTimeout(() => { + dispatchedObject.action(dispatchedObject.value); + }, dispatchedObject.delay); } } }, [props.eventState, dispatchObject]); diff --git a/src/scenes/MainScene.tsx b/src/scenes/MainScene.tsx index 6512bf3..dc33d44 100644 --- a/src/scenes/MainScene.tsx +++ b/src/scenes/MainScene.tsx @@ -7,7 +7,6 @@ import Preloader from "../components/Preloader"; import MainSceneIntro from "../components/MainSceneIntro"; import GrayPlanes from "../components/MainScene/GrayPlanes"; import MiddleRing from "../components/MainScene/MiddleRing"; -import Starfield from "../components/MainScene/Starfield"; import { useHudStore, useLainStore, useMainSceneStore } from "../store"; import GreenTextRenderer from "../components/TextRenderer/GreenTextRenderer"; import HUD from "../components/MainScene/HUD"; @@ -15,7 +14,8 @@ import YellowOrb from "../components/MainScene/YellowOrb"; import ActiveLevelNodes from "../components/MainScene/ActiveLevelNodes"; import YellowTextRenderer from "../components/TextRenderer/YellowTextRenderer"; import LevelSelection from "../components/MainScene/LevelSelection"; -import Pause from "../components/MainScene/Pause"; +import Pause from "../components/MainScene/PauseSubscene/Pause"; +import Starfield from "../components/MainScene/Starfield/Starfield"; const MainScene = () => { const currentSubscene = useMainSceneStore((state) => state.subscene); @@ -35,18 +35,18 @@ const MainScene = () => { - + {/**/} - +