From a80cf992bbe05c06d9860822fe5065839284c5d3 Mon Sep 17 00:00:00 2001 From: ad044 Date: Thu, 4 Feb 2021 20:39:38 +0400 Subject: [PATCH] bugfixes, more stable intro implementation i think --- src/components/MainScene/Lain.tsx | 39 +++--- .../MainScene/SyncedComponents/Site.tsx | 47 ++----- .../MainScene/SyncedComponents/Starfield.tsx | 11 +- .../handleMainKeyPress.ts | 2 + src/core/setters/main/site/levelManager.ts | 6 + src/core/setters/main/site/siteManager.ts | 6 + src/scenes/MainScene.tsx | 76 ++++++++++- src/store.ts | 12 +- src/utils/node-utils.ts | 119 ++++++++---------- 9 files changed, 179 insertions(+), 139 deletions(-) diff --git a/src/components/MainScene/Lain.tsx b/src/components/MainScene/Lain.tsx index 2975f29..44af314 100644 --- a/src/components/MainScene/Lain.tsx +++ b/src/components/MainScene/Lain.tsx @@ -40,6 +40,7 @@ type LainConstructorProps = { framesVertical: number; framesHorizontal: number; fps?: number; + shouldAnimate?: boolean; }; export const LainConstructor = (props: LainConstructorProps) => { @@ -58,7 +59,9 @@ export const LainConstructor = (props: LainConstructorProps) => { }); useFrame(() => { - animator.animate(); + if (props.shouldAnimate !== false) { + animator.animate(); + } }); return ( @@ -71,12 +74,14 @@ export const LainConstructor = (props: LainConstructorProps) => { ); }; -export const LainIntro = () => ( +export const LainIntro = (props: { shouldAnimate: boolean }) => ( ); @@ -350,7 +355,8 @@ export const LainPlayWithHair = () => ( ); type LainProps = { - shouldIntro: boolean; + shouldAnimate: boolean; + introFinished: boolean; }; const Lain = (props: LainProps) => { @@ -392,28 +398,17 @@ const Lain = (props: LainProps) => { return anims[lainMoveState as keyof typeof anims]; }, [lainMoveState]); - const [introFinished, setIntroFinished] = useState(false); - - useEffect(() => { - setTimeout(() => { - setIntroFinished(true); - }, 3900); - }, []); - - const stopIntroAnim = useMemo(() => { - return props.shouldIntro ? introFinished : true; - }, [introFinished, props.shouldIntro]); - const lainRef = useRef(); const glowColor = useMemo(() => new THREE.Color(2, 2, 2), []); const regularColor = useMemo(() => new THREE.Color(1, 1, 1), []); useEffect(() => { - if (wordSelected) + if (wordSelected) { setTimeout(() => { if (lainRef.current) lainRef.current.material.color = glowColor; }, 3100); + } }, [glowColor, wordSelected]); useFrame(() => { @@ -425,7 +420,11 @@ const Lain = (props: LainProps) => { return ( - {stopIntroAnim ? lainAnimationDispatch : } + {props.introFinished ? ( + lainAnimationDispatch + ) : ( + + )} ); diff --git a/src/components/MainScene/SyncedComponents/Site.tsx b/src/components/MainScene/SyncedComponents/Site.tsx index 5887c28..df631c1 100644 --- a/src/components/MainScene/SyncedComponents/Site.tsx +++ b/src/components/MainScene/SyncedComponents/Site.tsx @@ -43,7 +43,6 @@ export type SiteType = { }; type SiteProps = { - shouldIntro: boolean; introFinished: boolean; }; @@ -52,13 +51,17 @@ const Site = (props: SiteProps) => { const [rotState, setRot] = useSpring(() => ({ x: wordSelected ? 0 : useStore.getState().siteRot[0], - y: wordSelected ? 0 : useStore.getState().siteRot[1], + y: wordSelected + ? useStore.getState().oldSiteRot[1] + : useStore.getState().siteRot[1], config: { duration: 1200 }, })); const [posState, setPos] = useSpring(() => ({ y: wordSelected - ? 0 + ? -level_y_values[ + useStore.getState().oldLevel as keyof typeof level_y_values + ] : -level_y_values[ useStore.getState().activeLevel as keyof typeof level_y_values ], @@ -77,28 +80,6 @@ const Site = (props: SiteProps) => { })); }, [setPos, setRot]); - const introWrapperRef = useRef(); - - // imperative because having a spring here seemed to behave clunkily if that's even a word - // the site would pop back after having done the intro anim sometimes - useFrame(() => { - if (introWrapperRef.current) { - if (introWrapperRef.current.position.z < 0) { - introWrapperRef.current.position.z += 0.05; - } - if (introWrapperRef.current.rotation.x > 0) { - introWrapperRef.current.rotation.x -= 0.008; - } - } - }); - - useEffect(() => { - if (props.shouldIntro && introWrapperRef.current) { - introWrapperRef.current.rotation.x = Math.PI / 2; - introWrapperRef.current.position.z = -10; - } - }, [props.shouldIntro]); - const currentSite = useStore((state) => state.activeSite); const gameProgress = useStore((state) => state.gameProgress); @@ -110,17 +91,13 @@ const Site = (props: SiteProps) => { return ( - - - - - - - - + + + + + + ); diff --git a/src/components/MainScene/SyncedComponents/Starfield.tsx b/src/components/MainScene/SyncedComponents/Starfield.tsx index 64e3128..f69389d 100644 --- a/src/components/MainScene/SyncedComponents/Starfield.tsx +++ b/src/components/MainScene/SyncedComponents/Starfield.tsx @@ -3,7 +3,7 @@ import Star from "./Starfield/Star"; type StarfieldProps = { shouldIntro: boolean; - introFinished: boolean; + mainVisible: boolean; }; const Starfield = memo((props: StarfieldProps) => { @@ -39,13 +39,9 @@ const Starfield = memo((props: StarfieldProps) => { ]) ); - const [mainVisible, setMainVisible] = useState(false); const [introVisible, setIntroVisible] = useState(true); useEffect(() => { - setTimeout(() => { - setMainVisible(true); - }, 2800); setTimeout(() => { setIntroVisible(false); }, 3200); @@ -53,10 +49,7 @@ const Starfield = memo((props: StarfieldProps) => { return ( <> - + {posesBlueFromLeft.map((poses, idx) => ( { event: `${eventAnimation}_media`, scene: "media", siteRotY: siteRotY, + level: level.toString().padStart(2, "0"), }; case 6: if (activeNode.node_name.substr(0, 3) === "TaK") { @@ -117,6 +118,7 @@ const handleMainSceneEvent = (mainSceneContext: any) => { event: `${eventAnimation}_media`, scene: "media", siteRotY: siteRotY, + level: level.toString().padStart(2, "0"), }; } case 8: diff --git a/src/core/setters/main/site/levelManager.ts b/src/core/setters/main/site/levelManager.ts index fb95453..883770f 100644 --- a/src/core/setters/main/site/levelManager.ts +++ b/src/core/setters/main/site/levelManager.ts @@ -2,9 +2,15 @@ import { useStore } from "../../../../store"; const levelManager = (eventState: any) => { const setActiveLevel = useStore.getState().setActiveLevel; + const setOldLevel = useStore.getState().setOldLevel; const dispatchAction = (eventState: any) => { switch (eventState.event) { + case "throw_node_media": + case "rip_node_media": + return { + action: () => setOldLevel(eventState.level), + }; case "site_up": case "site_down": case "select_level_up": diff --git a/src/core/setters/main/site/siteManager.ts b/src/core/setters/main/site/siteManager.ts index c4c45e2..ba3b0f0 100644 --- a/src/core/setters/main/site/siteManager.ts +++ b/src/core/setters/main/site/siteManager.ts @@ -3,9 +3,15 @@ import { useStore } from "../../../../store"; const siteManager = (eventState: any) => { const setRotY = useStore.getState().setSiteRotY; const setRotX = useStore.getState().setSiteRotX; + const setOldRot = useStore.getState().setOldSiteRot; const dispatchAction = (eventState: any) => { switch (eventState.event) { + case "throw_node_media": + case "rip_node_media": + return { + action: () => setOldRot([0, eventState.siteRotY, 0]), + }; case "site_left": case "site_right": case "media_fstWord_select": diff --git a/src/scenes/MainScene.tsx b/src/scenes/MainScene.tsx index 3a620ae..917c692 100644 --- a/src/scenes/MainScene.tsx +++ b/src/scenes/MainScene.tsx @@ -1,5 +1,5 @@ import { OrbitControls } from "@react-three/drei"; -import React, { Suspense, useEffect, useState } from "react"; +import React, { Suspense, useEffect, useRef, useState } from "react"; import { useStore } from "../store"; import Pause from "../components/MainScene/PauseSubscene/Pause"; import LevelSelection from "../components/MainScene/SyncedComponents/LevelSelection"; @@ -11,8 +11,11 @@ import GrayPlanes from "../components/MainScene/SyncedComponents/GrayPlanes"; import Starfield from "../components/MainScene/SyncedComponents/Starfield"; import Site from "../components/MainScene/SyncedComponents/Site"; import Lain from "../components/MainScene/Lain"; +import * as THREE from "three"; +import { useFrame } from "react-three-fiber"; const MainScene = () => { + const intro = useStore((state) => state.intro); const [paused, setPaused] = useState(false); const subscene = useStore((state) => state.mainSubscene); @@ -37,23 +40,84 @@ const MainScene = () => { } }, [setWordSelected, wordSelected]); + useEffect(() => { + if (intro) { + if (introWrapperRef.current) { + introWrapperRef.current.rotation.x = Math.PI / 2; + introWrapperRef.current.position.z = -10; + } + setStarfieldIntro(false); + setLainIntroAnim(false); + setIntroFinished(false); + } + }, [intro]); + + const [starfieldIntro, setStarfieldIntro] = useState(false); + const [lainIntroAnim, setLainIntroAnim] = useState(false); + const [introFinished, setIntroFinished] = useState(false); + const introWrapperRef = useRef(); + + useFrame(() => { + if (intro && introWrapperRef.current) { + if ( + Math.round(introWrapperRef.current.position.z) === -3 && + !starfieldIntro + ) { + setStarfieldIntro(true); + } + if ( + Math.round(introWrapperRef.current.position.z) === -1 && + !lainIntroAnim + ) { + setLainIntroAnim(true); + } + + if ( + Math.round(introWrapperRef.current.position.z) === 0 && + Math.round(introWrapperRef.current.rotation.x) === 0 && + !introFinished + ) { + setIntroFinished(true); + } + + if (introWrapperRef.current.position.z < 0) { + introWrapperRef.current.position.z += 0.05; + } + if (introWrapperRef.current.rotation.x > 0) { + introWrapperRef.current.rotation.x -= 0.008; + } + } + }); + return ( - + - - - + + + + + + + + + + - diff --git a/src/store.ts b/src/store.ts index 4ae1bc4..7ea2476 100644 --- a/src/store.ts +++ b/src/store.ts @@ -31,9 +31,11 @@ type State = { // site activeSite: "a" | "b"; siteRot: number[]; + oldSiteRot: number[]; // level activeLevel: string; + oldLevel: string; // level selection selectedLevel: number; @@ -96,7 +98,6 @@ type State = { endMediaPlayedCount: number; // save state - siteSaveState: { a: { activeNode: NodeDataType; @@ -171,9 +172,13 @@ export const useStore = create( // site activeSite: "a", siteRot: [0, 0, 0], + // this one is used for word selection animation to start from the correct point + oldSiteRot: [0, 0, 0], // level activeLevel: "04", + // this one is used for word selection animation to start from the correct point + oldLevel: "04", // level selection selectedLevel: 4, @@ -301,9 +306,14 @@ export const useStore = create( nextRot[0] = to; return { siteRot: nextRot }; }), + setOldSiteRot: (to: number[]) => + set(() => ({ + oldSiteRot: to, + })), // level setters setActiveLevel: (to: string) => set(() => ({ activeLevel: to })), + setOldLevel: (to: string) => set(() => ({ oldLevel: to })), // level selection setters setSelectedLevel: (to: number) => set(() => ({ selectedLevel: to })), diff --git a/src/utils/node-utils.ts b/src/utils/node-utils.ts index 02b5eee..d1e7c0e 100644 --- a/src/utils/node-utils.ts +++ b/src/utils/node-utils.ts @@ -60,29 +60,19 @@ export const getNodeHud = (nodeMatrixIndices: { ] as keyof typeof node_huds ]; }; + +//visible = (global_final_viewcount > 0) && (req_final_viewcount <= global_final_viewcount + 1) export const isNodeVisible = ( node: NodeDataType, gameProgress: typeof unlocked_nodes -) => { - if (node) { - const unlockedBy = node.unlocked_by; - - let unlocked; - if (unlockedBy === "") unlocked = true; - else - unlocked = - gameProgress[unlockedBy as keyof typeof gameProgress].is_viewed; - - // visible = (global_final_viewcount > 0) && (req_final_viewcount <= global_final_viewcount + 1) - - return ( - unlocked && - gameProgress[node.node_name as keyof typeof gameProgress].is_visible - ); - } else { - return false; - } -}; +) => + node + ? (node.unlocked_by === "" || + gameProgress[node.unlocked_by as keyof typeof gameProgress] + .is_viewed) && + gameProgress[node.node_name as keyof typeof gameProgress].is_visible && + node.required_final_video_viewcount < 1 + : false; export const getVisibleNodesMatrix = ( matrixIdx: number, @@ -134,99 +124,92 @@ function* nextPos_left([row, col]: [number, number]) { const p = RowPrecedence(row); for (let c = col - 1; c > -1; c--) - for (let r = 0; r < 3; r++) - yield [p[r], c]; + for (let r = 0; r < 3; r++) yield [p[r], c]; } function* nextPos_right([row, col]: [number, number]) { const p = RowPrecedence(row); - for (let c = col + 1; c < 4; c++) - for (let r = 0; r < 3; r++) - yield [p[r], c]; + for (let c = col + 1; c < 4; c++) for (let r = 0; r < 3; r++) yield [p[r], c]; } function* nextPos_up([row, col]: [number, number]) { const p = ColPrecedence(col); for (let r = row - 1; r > -1; r--) - for (let c = 0; c < 4; c++) - yield [r, p[c]]; + for (let c = 0; c < 4; c++) yield [r, p[c]]; } function* nextPos_down([row, col]: [number, number]) { const p = ColPrecedence(col); - for (let r = row + 1; r < 3; r++) - for (let c = 0; c < 4; c++) - yield [r, p[c]]; + for (let r = row + 1; r < 3; r++) for (let c = 0; c < 4; c++) yield [r, p[c]]; } function move(direction: string, [matrix, level]: [number, number]) { switch (direction) { - case "left": matrix = matrix + 1 > 8 ? 1 : matrix + 1; break; - case "right": matrix = matrix - 1 < 1 ? 8 : matrix - 1; break; - case "up": level++; break; - case "down": level--; break; + case "left": + matrix = matrix + 1 > 8 ? 1 : matrix + 1; + break; + case "right": + matrix = matrix - 1 < 1 ? 8 : matrix - 1; + break; + case "up": + level++; + break; + case "down": + level--; + break; } return [matrix, level]; } -export function findNode -( +export function findNode( direction: string, - {matrixIdx, rowIdx, colIdx}: - {matrixIdx: number, rowIdx: number, colIdx: number}, + { + matrixIdx, + rowIdx, + colIdx, + }: { matrixIdx: number; rowIdx: number; colIdx: number }, level: number, currentSite: string, gameProgress: any -) -: any | undefined -{ +): any | undefined { const funcs: any = { - left: [ - nextPos_left, - ([r]: [number, number]) => nextPos_right([r, -1]) - ], - right: [ - nextPos_right, - ([r]: [number, number]) => nextPos_left([r, 4]) - ], - up: [ - nextPos_up, - ([, c]: [number, number]) => nextPos_up([3, c]) - ], - down: [ - nextPos_down, - ([, c]: [number, number]) => nextPos_down([-1, c]) - ] + left: [nextPos_left, ([r]: [number, number]) => nextPos_right([r, -1])], + right: [nextPos_right, ([r]: [number, number]) => nextPos_left([r, 4])], + up: [nextPos_up, ([, c]: [number, number]) => nextPos_up([3, c])], + down: [nextPos_down, ([, c]: [number, number]) => nextPos_down([-1, c])], }; const nextPos = funcs[direction]; - for (let i = 0; i < 2; i++) { const nodes = getVisibleNodesMatrix( - matrixIdx, level, - currentSite, gameProgress + matrixIdx, + level, + currentSite, + gameProgress ); for (const [r, c] of nextPos[i]([rowIdx, colIdx])) { const node = nodes[r][c]; - if (node) return { - node, + if (node) + return { + node, - matrixIndices: { - matrixIdx, - rowIdx: r, colIdx: c - }, + matrixIndices: { + matrixIdx, + rowIdx: r, + colIdx: c, + }, - didMove: Boolean(i) - }; + didMove: Boolean(i), + }; } [matrixIdx, level] = move(direction, [matrixIdx, level]);