From ba56e5451fec46ad2ef7807d0b8670888ccee522 Mon Sep 17 00:00:00 2001 From: ad044 Date: Sat, 12 Sep 2020 21:45:51 +0400 Subject: [PATCH] separated main intro scene into its own file, ported the animation to react-spring --- src/components/HUD/HUDActiveAtom.tsx | 5 ++ src/components/InputHandler.tsx | 6 +- src/components/Lights.tsx | 8 +- src/components/MainScene/MainGroupAtom.tsx | 16 ++++ src/components/MainScene/MainScene.tsx | 81 ++++++++------------- src/components/MainScene/MainSceneIntro.tsx | 74 +++++++++++++++++++ src/components/{ => Orb}/Orb.tsx | 2 +- src/components/Orb/OrbAtom.tsx | 6 ++ src/components/OrthoCamera/OrthoCamera.tsx | 23 +++--- src/components/Starfield/Starfield.tsx | 25 ++++--- src/components/Starfield/StarfieldAtom.tsx | 8 +- 11 files changed, 168 insertions(+), 86 deletions(-) create mode 100644 src/components/MainScene/MainGroupAtom.tsx create mode 100644 src/components/MainScene/MainSceneIntro.tsx rename src/components/{ => Orb}/Orb.tsx (98%) create mode 100644 src/components/Orb/OrbAtom.tsx diff --git a/src/components/HUD/HUDActiveAtom.tsx b/src/components/HUD/HUDActiveAtom.tsx index 6116daf..b8cb9de 100644 --- a/src/components/HUD/HUDActiveAtom.tsx +++ b/src/components/HUD/HUDActiveAtom.tsx @@ -4,3 +4,8 @@ export const hudActiveAtom = atom({ key: "hudActiveAtom", default: 1, }); + +export const hudVisibilityAtom = atom({ + key: "hudVisibilityAtom", + default: false, +}); diff --git a/src/components/InputHandler.tsx b/src/components/InputHandler.tsx index bf85a1a..4b5eb4a 100644 --- a/src/components/InputHandler.tsx +++ b/src/components/InputHandler.tsx @@ -53,7 +53,7 @@ const InputHandler = () => { const setCurrentHUDElement = useSetRecoilState(currentHUDAtom); - const sethudActive = useSetRecoilState(hudActiveAtom); + const setHudActive = useSetRecoilState(hudActiveAtom); const setCamPosY = useSetRecoilState(camPosYAtom); const setCamRotY = useSetRecoilState(camRotYAtom); @@ -136,8 +136,8 @@ const InputHandler = () => { ); const updateHUD = useCallback(() => { - sethudActive((prev: number) => Number(!prev)); - }, [sethudActive]); + setHudActive((prev: number) => Number(!prev)); + }, [setHudActive]); const moveDispatcher = useCallback( (move: string, key: string) => { diff --git a/src/components/Lights.tsx b/src/components/Lights.tsx index 6ec42ee..506b17b 100644 --- a/src/components/Lights.tsx +++ b/src/components/Lights.tsx @@ -1,13 +1,9 @@ import React, { memo } from "react"; -type LightProps = { - ambientLightVal: number; -}; - -const Lights = memo((props: LightProps) => { +const Lights = memo(() => { return ( <> - + diff --git a/src/components/MainScene/MainGroupAtom.tsx b/src/components/MainScene/MainGroupAtom.tsx new file mode 100644 index 0000000..43c20b6 --- /dev/null +++ b/src/components/MainScene/MainGroupAtom.tsx @@ -0,0 +1,16 @@ +import { atom } from "recoil"; + +export const mainGroupPosYAtom = atom({ + key: "mainGroupPosYAtom", + default: -2.5, +}); + +export const mainGroupPosZAtom = atom({ + key: "mainGroupPosZAtom", + default: -9.5, +}); + +export const mainGroupRotXAtom = atom({ + key: "mainGroupRotXAtom", + default: 1.5, +}); diff --git a/src/components/MainScene/MainScene.tsx b/src/components/MainScene/MainScene.tsx index ea0593e..772bc1f 100644 --- a/src/components/MainScene/MainScene.tsx +++ b/src/components/MainScene/MainScene.tsx @@ -1,77 +1,51 @@ import { a, useSpring } from "@react-spring/three"; import { OrbitControls } from "drei"; import React, { Suspense, useEffect, useRef, useState } from "react"; -import { useFrame } from "react-three-fiber"; import Hub from "../Hub"; -import Lain, { LainIntro, LainStanding } from "../Lain/Lain"; +import Lain, { LainIntro } from "../Lain/Lain"; import Lights from "../Lights"; import OrthoCamera from "../OrthoCamera/OrthoCamera"; import Preloader from "../Preloader"; import Starfield from "../Starfield/Starfield"; -import * as THREE from "three"; import { useRecoilValue, useSetRecoilState } from "recoil"; import { lainMoveStateAtom, lainMovingAtom } from "../Lain/LainAtom"; import { camPosYAtom, camRotYAtom } from "./CameraAtom"; import InputHandler from "../InputHandler"; +import MainSceneIntro from "./MainSceneIntro"; +import { + mainGroupPosYAtom, + mainGroupPosZAtom, + mainGroupRotXAtom, +} from "./MainGroupAtom"; const MainScene = () => { const setLainMoving = useSetRecoilState(lainMovingAtom); const setLainMoveState = useSetRecoilState(lainMoveStateAtom); - - const [isIntro, setIsIntro] = useState(true); + const mainGroupPosY = useRecoilValue(mainGroupPosYAtom); + const mainGroupPosZ = useRecoilValue(mainGroupPosZAtom); + const mainGroupRotX = useRecoilValue(mainGroupRotXAtom); const camPosY = useRecoilValue(camPosYAtom); const camRotY = useRecoilValue(camRotYAtom); - const [ambientLightVal, setAmbientLightVal] = useState(0.4); - const cameraState = useSpring({ camPosY: camPosY, camRotY: camRotY, config: { duration: 1200 }, }); - const groupRef = useRef(); - - useFrame(() => { - if (isIntro) { - if (groupRef.current) { - if (groupRef.current!.rotation.x > 0) { - if (groupRef.current!.position.z > -1) { - groupRef.current!.rotation.x -= 0.015; - } else { - // if the position z is at a certain point speed up the rotation - groupRef.current!.rotation.x -= 0.01; - } - } - if (groupRef.current!.position.y > 0) { - groupRef.current!.position.y -= 0.015; - } - - if (groupRef.current!.position.z < 0) { - groupRef.current!.position.z += 0.04; - } - - // if the rotation hits this value that means that the intro is finished. - // using a settimeout or something similar resulted in clunkiness, since it was dependant - // on load times. - if ( - parseFloat(groupRef.current!.rotation.x.toPrecision(2)) === -0.005 - ) { - setLainMoving(false); - setLainMoveState(); - - setTimeout(() => { - setIsIntro(false); - setAmbientLightVal(1.0); - document.getElementsByTagName("canvas")[0].className = - "hub-background"; - }, 300); - } - } - } + const mainGroupStatePos = useSpring({ + mainGroupPosY: mainGroupPosY, + mainGroupPosZ: mainGroupPosZ, + config: { duration: 3644 }, }); + const mainGroupStateRot = useSpring({ + mainGroupRotX: mainGroupRotX, + config: { duration: 1500 }, + }); + + // set lain intro spritesheet before the page loads fully useEffect(() => { setLainMoving(true); setLainMoveState(); @@ -84,15 +58,20 @@ const MainScene = () => { rotation-y={cameraState.camRotY} > - + + - - - + + + - + diff --git a/src/components/MainScene/MainSceneIntro.tsx b/src/components/MainScene/MainSceneIntro.tsx new file mode 100644 index 0000000..d533ff6 --- /dev/null +++ b/src/components/MainScene/MainSceneIntro.tsx @@ -0,0 +1,74 @@ +import React, { memo, useEffect } from "react"; +import { useSetRecoilState } from "recoil"; +import { hudActiveAtom, hudVisibilityAtom } from "../HUD/HUDActiveAtom"; +import { + mainGroupPosYAtom, + mainGroupPosZAtom, + mainGroupRotXAtom, +} from "./MainGroupAtom"; +import { LainStanding } from "../Lain/Lain"; +import { lainMoveStateAtom, lainMovingAtom } from "../Lain/LainAtom"; +import { orbVisibilityAtom } from "../Orb/OrbAtom"; +import { introStarfieldVisibilityAtom } from "../Starfield/StarfieldAtom"; + +// ghost component to manipulate the intro animation for the main scene. + +// we separate this file because having something like this +// inside tags makes it behave in a more stable manner +// by waiting for the components to load and synchronously calling the functions. +const MainSceneIntro = memo(() => { + const setHudActive = useSetRecoilState(hudActiveAtom); + + const setHudVisible = useSetRecoilState(hudVisibilityAtom); + const setOrbVisible = useSetRecoilState(orbVisibilityAtom); + + const setLainMoving = useSetRecoilState(lainMovingAtom); + const setLainMoveState = useSetRecoilState(lainMoveStateAtom); + + const setIntroStarfieldVisible = useSetRecoilState( + introStarfieldVisibilityAtom + ); + + const setMainGroupPosY = useSetRecoilState(mainGroupPosYAtom); + const setMainGroupPosZ = useSetRecoilState(mainGroupPosZAtom); + const setMainGroupRotX = useSetRecoilState(mainGroupRotXAtom); + + useEffect(() => { + setMainGroupPosY(0); + setMainGroupPosZ(0); + setTimeout(() => { + setMainGroupRotX(0); + }, 2400); + + setHudActive((prev: number) => Number(!prev)); + setTimeout(() => { + setLainMoving(false); + setLainMoveState(); + + setOrbVisible(true); + setHudVisible(true); + + setIntroStarfieldVisible(false); + + setHudActive((prev: number) => Number(!prev)); + + setTimeout(() => { + document.getElementsByTagName("canvas")[0].className = "hub-background"; + }, 300); + }, 3860); + }, [ + setHudVisible, + setOrbVisible, + setIntroStarfieldVisible, + setHudActive, + setMainGroupRotX, + setMainGroupPosZ, + setMainGroupPosY, + setLainMoving, + setLainMoveState, + ]); + + return <>; +}); + +export default MainSceneIntro; diff --git a/src/components/Orb.tsx b/src/components/Orb/Orb.tsx similarity index 98% rename from src/components/Orb.tsx rename to src/components/Orb/Orb.tsx index 79566c9..2d3e855 100644 --- a/src/components/Orb.tsx +++ b/src/components/Orb/Orb.tsx @@ -1,7 +1,7 @@ import React, { memo, useRef, useState } from "react"; import { useFrame, useLoader } from "react-three-fiber"; import * as THREE from "three"; -import orbSprite from "../static/sprites/orb.png"; +import orbSprite from "../../static/sprites/orb.png"; // initialize outside the component otherwise it gets overwritten when it rerenders let orbIdx = 0; diff --git a/src/components/Orb/OrbAtom.tsx b/src/components/Orb/OrbAtom.tsx new file mode 100644 index 0000000..e5e6db8 --- /dev/null +++ b/src/components/Orb/OrbAtom.tsx @@ -0,0 +1,6 @@ +import { atom } from "recoil"; + +export const orbVisibilityAtom = atom({ + key: "orbVisibilityAtom", + default: false, +}); diff --git a/src/components/OrthoCamera/OrthoCamera.tsx b/src/components/OrthoCamera/OrthoCamera.tsx index c4320dd..0ef50e4 100644 --- a/src/components/OrthoCamera/OrthoCamera.tsx +++ b/src/components/OrthoCamera/OrthoCamera.tsx @@ -1,23 +1,24 @@ -import React, { useMemo, useRef } from "react"; +import React, { memo, useMemo, useRef } from "react"; import { useFrame, useThree } from "react-three-fiber"; import { Scene } from "three"; import HUDElement from "../HUD/HUDElement"; -import Orb from "../Orb"; +import Orb from "../Orb/Orb"; import { useRecoilValue } from "recoil"; import { orthoCamPosYAtom } from "./OrthoCameraAtom"; import { useSpring, a } from "@react-spring/three"; +import { orbVisibilityAtom } from "../Orb/OrbAtom"; +import { hudVisibilityAtom } from "../HUD/HUDActiveAtom"; -interface OrthoCameraProps { - orbVisibility: boolean; - hudVisibility: boolean; -} - -const OrthoCamera = (props: OrthoCameraProps) => { +const OrthoCamera = memo(() => { const { gl, scene, camera } = useThree(); const virtualScene = useMemo(() => new Scene(), []); const virtualCam = useRef(); const orthoCameraPosY = useRecoilValue(orthoCamPosYAtom); + const orbVisible = useRecoilValue(orbVisibilityAtom); + + const hudVisible = useRecoilValue(hudVisibilityAtom); + const orthoCameraState = useSpring({ orthoCameraPosY: orthoCameraPosY, config: { duration: 1200 }, @@ -38,10 +39,10 @@ const OrthoCamera = (props: OrthoCameraProps) => { position={[0, 0, 10]} position-y={orthoCameraState.orthoCameraPosY} > - - + + ); -}; +}); export default OrthoCamera; diff --git a/src/components/Starfield/Starfield.tsx b/src/components/Starfield/Starfield.tsx index 0be1ab1..cf9fade 100644 --- a/src/components/Starfield/Starfield.tsx +++ b/src/components/Starfield/Starfield.tsx @@ -1,4 +1,4 @@ -import { a, Interpolation, useSpring } from "@react-spring/three"; +import { a, useSpring } from "@react-spring/three"; import React, { createRef, memo, @@ -10,7 +10,10 @@ import React, { } from "react"; import { useFrame } from "react-three-fiber"; import * as THREE from "three"; -import { starfieldPosYAtom } from "./StarfieldAtom"; +import { + introStarfieldVisibilityAtom, + starfieldPosYAtom, +} from "./StarfieldAtom"; import { useRecoilValue } from "recoil"; type StarRefsAndInitialPoses = [ @@ -18,10 +21,6 @@ type StarRefsAndInitialPoses = [ number[][] ][]; -type StarfieldProps = { - introStarfieldVisible: boolean; -}; - type StarfieldObjectData = { starPoses: number[][]; ref: React.MutableRefObject[]>; @@ -40,13 +39,15 @@ type IntroStarfieldObjectData = { | undefined; }; -const Starfield = memo((props: StarfieldProps) => { +const Starfield = memo(() => { const introStarfieldGroupRef = useRef(); const [mainStarfieldVisible, setMainStarfieldVisible] = useState(false); const starfieldPosY = useRecoilValue(starfieldPosYAtom); + const introStarfieldVisible = useRecoilValue(introStarfieldVisibilityAtom); + const starfieldState = useSpring({ starfieldPosY: starfieldPosY, config: { duration: 1200 }, @@ -173,7 +174,7 @@ const Starfield = memo((props: StarfieldProps) => { ); useFrame(() => { - if (props.introStarfieldVisible) { + if (introStarfieldVisible) { introStarfieldGroupRef.current!.position.y += 0.2; } if (mainStarfieldVisible) { @@ -281,21 +282,21 @@ const Starfield = memo((props: StarfieldProps) => { <> {introStarfieldObjects.map((obj: IntroStarfieldObjectData) => obj.starPoses.map((pos: number[], idx: number) => { return ( - +