PERFORMACNE GAINS BROTHER

This commit is contained in:
ad044 2021-01-26 23:37:33 +04:00
parent abbd510941
commit 4f2298235a
14 changed files with 158 additions and 246 deletions

View file

@ -9,6 +9,7 @@ import MiddleRing from "./SyncedComponents/MiddleRing";
import MainSceneEventManager from "../../core/StateManagers/MainSceneEventManager";
import Pause from "./PauseSubscene/Pause";
import { a } from "@react-spring/three";
import Lain from "./Lain";
type SyncedComponentLoaderProps = {
paused: boolean;
@ -56,6 +57,7 @@ const SyncedComponentLoader = (props: SyncedComponentLoaderProps) => {
<MainSceneEventManager
loaded={props.shouldIntro ? introFinished : true}
/>
<Lain shouldIntro={props.shouldIntro} />
</>
);
};

View file

@ -1,15 +1,14 @@
import React, { memo, useEffect, useRef, useState } from "react";
import React, { memo, useEffect, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import bigHud from "../../../static/sprite/big_hud.png";
import longHud from "../../../static/sprite/long_hud.png";
import boringHud from "../../../static/sprite/long_hud_boring.png";
import { a } from "@react-spring/three";
import { useStore } from "../../../store";
import { getNodeHud } from "../../../core/nodeSelector";
import lerp from "../../../core/utils/lerp";
import GreenTextRenderer from "../../TextRenderer/GreenTextRenderer";
import MediaSceneEventManager from "../../../core/StateManagers/MediaSceneEventManager";
import usePrevious from "../../../hooks/usePrevious";
export type HUDType = {
mirrored: number;
@ -33,15 +32,18 @@ export type HUDType = {
};
const HUD = memo(() => {
const greenText = ["d", "i"];
const activeRef = useRef(true);
const currentHudRef = useRef(
getNodeHud(useStore.getState().activeNodeMatrixIndices)
getNodeHud(useStore.getState().activeNode.matrixIndices!)
);
const activeNodeMatrixIndices = useStore(
(state) => state.activeNodeMatrixIndices
(state) => state.activeNode.matrixIndices
);
const siteRotY = useStore((state) => state.siteRot[1]);
const sitePosY = useStore((state) => state.sitePos[1]);
const prevData = usePrevious({ siteRotY, sitePosY });
// this part is imperative because it performs a lot better than having a toggleable spring.
useFrame(() => {
if (
longHudRef.current &&
@ -84,45 +86,66 @@ const HUD = memo(() => {
});
useEffect(() => {
if (activeRef.current) {
activeRef.current = false;
setTimeout(() => {
const hud = getNodeHud(activeNodeMatrixIndices);
if (
longHudRef.current &&
bigHudRef.current &&
boringHudRef.current &&
greenTextRef.current
) {
longHudRef.current.position.y = hud.long.position[1];
boringHudRef.current.position.y = hud.boring.position[1];
bigHudRef.current.position.y = hud.big.position[1];
greenTextRef.current.position.y = hud.medium_text.position[1];
if (activeRef.current !== undefined) {
if (prevData?.siteRotY !== siteRotY || prevData?.sitePosY !== sitePosY) {
activeRef.current = false;
} else {
const wasHidden = !activeRef.current;
activeRef.current = false;
setTimeout(
() => {
const hud = getNodeHud(activeNodeMatrixIndices!);
if (
longHudRef.current &&
bigHudRef.current &&
boringHudRef.current &&
greenTextRef.current
) {
longHudRef.current.position.y = hud.long.position[1];
boringHudRef.current.position.y = hud.boring.position[1];
bigHudRef.current.position.y = hud.big.position[1];
greenTextRef.current.position.y = hud.medium_text.position[1];
longHudRef.current.position.x = hud.long.initial_position[0];
boringHudRef.current.position.x = hud.boring.initial_position[0];
bigHudRef.current.position.x = hud.big.initial_position[0];
greenTextRef.current.position.x = hud.medium_text.initial_position[0];
longHudRef.current.position.x = hud.long.initial_position[0];
boringHudRef.current.position.x = hud.boring.initial_position[0];
bigHudRef.current.position.x = hud.big.initial_position[0];
greenTextRef.current.position.x =
hud.medium_text.initial_position[0];
if (hud.mirrored) {
longHudRef.current.scale.x = -Math.abs(longHudRef.current.scale.x);
boringHudRef.current.scale.x = -Math.abs(
boringHudRef.current.scale.x
);
bigHudRef.current.scale.x = -Math.abs(bigHudRef.current.scale.x);
} else {
longHudRef.current.scale.x = Math.abs(longHudRef.current.scale.x);
boringHudRef.current.scale.x = Math.abs(
boringHudRef.current.scale.x
);
bigHudRef.current.scale.x = Math.abs(bigHudRef.current.scale.x);
}
currentHudRef.current = hud;
activeRef.current = true;
}
}, 500);
if (hud.mirrored) {
longHudRef.current.scale.x = -Math.abs(
longHudRef.current.scale.x
);
boringHudRef.current.scale.x = -Math.abs(
boringHudRef.current.scale.x
);
bigHudRef.current.scale.x = -Math.abs(
bigHudRef.current.scale.x
);
} else {
longHudRef.current.scale.x = Math.abs(
longHudRef.current.scale.x
);
boringHudRef.current.scale.x = Math.abs(
boringHudRef.current.scale.x
);
bigHudRef.current.scale.x = Math.abs(bigHudRef.current.scale.x);
}
currentHudRef.current = hud;
activeRef.current = true;
}
},
wasHidden ? 0 : 500
);
}
}
}, [activeNodeMatrixIndices]);
}, [
activeNodeMatrixIndices,
prevData?.sitePosY,
prevData?.siteRotY,
sitePosY,
siteRotY,
]);
const longHudRef = useRef<THREE.Object3D>();
const boringHudRef = useRef<THREE.Object3D>();
@ -133,10 +156,9 @@ const HUD = memo(() => {
const boringHudTex = useLoader(THREE.TextureLoader, boringHud);
const bigHudTex = useLoader(THREE.TextureLoader, bigHud);
// console.log("rend");
return (
<group position={[0, 0, 10]}>
<a.mesh
<mesh
scale={[1, 0.03, 1]}
renderOrder={2}
ref={longHudRef}
@ -149,8 +171,8 @@ const HUD = memo(() => {
transparent={true}
depthTest={false}
/>
</a.mesh>
<a.mesh
</mesh>
<mesh
scale={[1, 0.03, 1]}
renderOrder={2}
ref={boringHudRef}
@ -163,8 +185,8 @@ const HUD = memo(() => {
transparent={true}
depthTest={false}
/>
</a.mesh>
<a.mesh
</mesh>
<mesh
scale={[0.5, 0.06, 1]}
renderOrder={2}
ref={bigHudRef}
@ -177,10 +199,10 @@ const HUD = memo(() => {
transparent={true}
depthTest={false}
/>
</a.mesh>
<a.group position-z={-8.7} scale={[0.02, 0.035, 0.02]} ref={greenTextRef}>
</mesh>
<group position-z={-8.7} scale={[0.02, 0.035, 0.02]} ref={greenTextRef}>
<GreenTextRenderer />
</a.group>
</group>
</group>
);
});

View file

@ -1,13 +1,13 @@
import React, { Suspense, useEffect, useMemo } from "react";
import React, { Suspense, useMemo, useRef } from "react";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
import ActiveLevelNodes from "./Site/ActiveLevelNodes";
import Rings from "./Site/Rings";
import site_a from "../../../resources/site_a.json";
import site_b from "../../../resources/site_b.json";
import game_progress from "../../../resources/initial_progress.json";
import NodeAnimations from "./Site/NodeAnimations";
import InactiveLevelNodes from "./Site/InactiveLevelNodes";
import { useFrame } from "react-three-fiber";
import * as THREE from "three";
import lerp from "../../../core/utils/lerp";
export type NodeDataType = {
id: string;
@ -23,6 +23,11 @@ export type NodeDataType = {
upgrade_requirement: number;
protocol_lines: { 1: string; 2: string; 3: string; 4: string };
words: { 1: string; 2: string; 3: string };
matrixIndices?: {
matrixIdx: number;
rowIdx: number;
colIdx: number;
};
};
export type LevelType = {
@ -48,22 +53,24 @@ const Site = (props: SiteProps) => {
config: { duration: 1200 },
});
const introSiteState = useSpring({
posZ: 0,
rotX: 0,
from: {
posZ: -10,
rotX: Math.PI / 2,
},
config: { duration: 3400 },
const introWrapperRef = useRef<THREE.Object3D>();
// 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;
}
}
});
return (
<Suspense fallback={null}>
<a.group
rotation-x={props.shouldIntro ? introSiteState.rotX : 0}
position-z={props.shouldIntro ? introSiteState.posZ : 0}
>
<a.group ref={introWrapperRef} position-z={-10} rotation-x={Math.PI / 2}>
<a.group rotation-x={siteState.siteRotX}>
<a.group
rotation-y={siteState.siteRotY}

View file

@ -4,14 +4,15 @@ 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, memo } from "react";
import React, { memo, useEffect, useMemo } from "react";
import { useStore } from "../../store";
const BigLetter = memo(
(props: {
color: string;
letter: string;
letterIdx: number;
xOffset: number;
xOffset?: number;
}) => {
const tex = useMemo(
() =>
@ -79,14 +80,24 @@ const BigLetter = memo(
return geometry;
}, [letterData, lineYOffset]);
const letterState = useSpring({
xOffset: props.letterIdx + 0.3 + (props.letterIdx + 0.3) * props.xOffset,
const activeNode = useStore((state) => state.activeNode);
const [shrinkState, set] = useSpring(() => ({
x: props.letterIdx + 0.3,
config: { duration: 200 },
});
}));
useEffect(() => {
set({ x: 0 });
setTimeout(() => {
set({ x: props.letterIdx + 0.3 });
}, 1200);
}, [activeNode, props.letterIdx, set]);
return (
<a.mesh
position-x={letterState.xOffset}
position-x={shrinkState.x}
position-y={-letterData[4] / 12.5}
scale={[1, 1, 0]}
geometry={geom}

View file

@ -98,8 +98,6 @@ const GreenTextRenderer = memo(() => {
});
}, [colorTexture, textToRender]);
console.log("rend");
return <>{text}</>;
});

View file

@ -1,38 +1,33 @@
import React, { useEffect, useRef } from "react";
import React, { useEffect, useState } from "react";
import { useStore } from "../../store";
import { a, useTrail } from "@react-spring/three";
import BigLetter from "./BigLetter";
import { getNodeHud } from "../../core/nodeSelector";
const YellowTextRenderer = (props: { visible?: boolean }) => {
const xOffset = useStore((state) => state.bigTextXOffset);
const visible = useStore((state) => state.bigTextVisible);
const color = useStore((state) => state.bigTextColor);
const textRef = useRef(useStore.getState().bigText.split(""));
const activeNode = useStore((state) => state.activeNode);
const [trail, set] = useTrail(textRef.current.length, () => ({
const [text, setText] = useState(useStore.getState().bigText.split(""));
const [trail, set] = useTrail(text.length, () => ({
posX: useStore.getState().bigTextPos[0],
posY: useStore.getState().bigTextPos[1],
config: { duration: 280 },
}));
useEffect(
() =>
useStore.subscribe(
(state) => {
textRef.current = (state as any).bigText.split("");
},
(state) => state
),
[]
);
useEffect(() => {
useStore.subscribe(set, (state) => ({
posX: state.bigTextPos[0],
posY: state.bigTextPos[1],
}));
}, [set]);
const hud = getNodeHud(activeNode.matrixIndices!);
setTimeout(() => {
set({ posX: hud.big_text[0], posY: hud.big_text[1] });
}, 400);
setTimeout(() => {
setText(activeNode.node_name.split(""));
}, 1000);
}, [activeNode, set]);
return (
<group position={[0, 0, 10]} visible={props.visible && visible}>
@ -46,8 +41,7 @@ const YellowTextRenderer = (props: { visible?: boolean }) => {
>
<BigLetter
color={color}
xOffset={xOffset}
letter={textRef.current[idx]}
letter={text[idx]}
letterIdx={idx}
key={idx}
/>

View file

@ -27,9 +27,6 @@ const GameLoader = (props: StateManagerProps) => {
// node setter
const setActiveNode = useStore((state) => state.setNode);
const setNodeMatrixIndices = useStore(
(state) => state.setNodeMatrixIndices
);
// node hud setter
const setHud = useStore((state) => state.setHud);

View file

@ -3,7 +3,6 @@ import { useStore } 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";
@ -26,17 +25,13 @@ const MainSceneEventManager = (props: MainSceneEventManagerProps) => {
// all the possible context needed to calculate new state
const currentSite = useStore((state) => state.activeSite);
const activeNodeId = useStore((state) => state.activeNode.id);
const nodeMatrixIndices = useStore(
(state) => state.activeNodeMatrixIndices
);
const nodeMatrixIndices = useStore((state) => state.activeNode.matrixIndices);
const siteRotY = useStore((state) => state.siteRot[1]);
const sitePosY = useStore((state) => state.sitePos[1]);
const activeLevel = useStore((state) => state.activeLevel);
const mainSubscene = useStore((state) => state.mainSubscene);
const selectedLevel = useStore((state) => state.selectedLevel);
const pauseMatrixIdx = useStore(
(state) => state.pauseComponentMatrixIdx
);
const pauseMatrixIdx = useStore((state) => state.pauseComponentMatrixIdx);
const activePauseComponent = useStore(
useCallback((state) => state.pauseComponentMatrix[pauseMatrixIdx], [
pauseMatrixIdx,
@ -143,7 +138,6 @@ const MainSceneEventManager = (props: MainSceneEventManagerProps) => {
return (
<>
<NodeManager eventState={eventState!} />
<NodeHUDManager eventState={eventState!} />
<SiteManager eventState={eventState!} />
<LainManager eventState={eventState!} />
<MiddleRingManager eventState={eventState!} />

View file

@ -48,29 +48,6 @@ const BigTextManager = (props: StateManagerProps) => {
[setPos, setText, setXOffset]
);
const animateYellowTextWithoutMove = useCallback(
(hud: HUDType, node: NodeDataType) => {
// make current hud big text shrink
setXOffset(-1);
setTimeout(() => {
// animate it to new pos x/y
setPos(hud.big_text);
}, 400);
setTimeout(() => {
// set new text according to the node name
setText(node.node_name);
}, 1000);
setTimeout(() => {
// unshrink text
setXOffset(0);
}, 1200);
},
[setPos, setText, setXOffset]
);
const initializeLevelSelection = useCallback(() => {
setXOffset(-1);
@ -155,11 +132,6 @@ const BigTextManager = (props: StateManagerProps) => {
action: animateYellowTextWithMove,
value: [-Math.PI / 4, 0, eventState.hud, eventState.node, 1100],
};
case "change_node":
return {
action: animateYellowTextWithoutMove,
value: [eventState.hud, eventState.node],
};
case "level_selection_back":
return {
action: levelSelectionBack,
@ -179,7 +151,6 @@ const BigTextManager = (props: StateManagerProps) => {
},
[
animateYellowTextWithMove,
animateYellowTextWithoutMove,
initializeLevelSelection,
levelSelectionBack,
toggleVisibleAfterLevelSelect,
@ -194,12 +165,7 @@ const BigTextManager = (props: StateManagerProps) => {
(dispatchedObject.action as any).apply(null, dispatchedObject.value);
}
}
}, [
animateYellowTextWithMove,
animateYellowTextWithoutMove,
props.eventState,
dispatchObject,
]);
}, [animateYellowTextWithMove, props.eventState, dispatchObject]);
return null;
};

View file

@ -1,71 +0,0 @@
import { useCallback, useEffect } from "react";
import { useStore } from "../../../store";
import { StateManagerProps } from "../EventManager";
import { HUDType } from "../../../components/MainScene/SyncedComponents/HUD";
const NodeHUDManager = (props: StateManagerProps) => {
const set = useStore((state) => state.setHud);
const toggleActive = useStore((state) => state.toggleHudActive);
const moveAndChangeNode = useCallback(
(hud: HUDType) => {
toggleActive();
setTimeout(() => {
set(hud);
toggleActive();
}, 3900);
},
[set, toggleActive]
);
const selectLevelAnimation = useCallback(
(hud: HUDType) => {
setTimeout(() => {
set(hud);
toggleActive();
}, 3900);
},
[set, toggleActive]
);
const dispatchObject = useCallback(
(eventState: { event: string; hud: HUDType }) => {
switch (eventState.event) {
case "site_up":
case "site_down":
case "site_left":
case "site_right":
return {
action: moveAndChangeNode,
value: [eventState.hud],
};
case "toggle_level_selection":
case "level_selection_back":
return {
action: toggleActive,
};
case "select_level_up":
case "select_level_down":
return {
action: selectLevelAnimation,
value: [eventState.hud],
};
}
},
[moveAndChangeNode, selectLevelAnimation, toggleActive]
);
useEffect(() => {
if (props.eventState) {
const dispatchedObject = dispatchObject(props.eventState);
if (dispatchedObject) {
(dispatchedObject.action as any).apply(null, dispatchedObject.value);
}
}
}, [props.eventState, toggleActive, dispatchObject]);
return null;
};
export default NodeHUDManager;

View file

@ -8,9 +8,6 @@ const NodeManager = (props: StateManagerProps) => {
const setActiveNodePos = useStore((state) => state.setNodePos);
const setActiveNodeRot = useStore((state) => state.setNodeRot);
const setActiveNodeState = useStore((state) => state.setNodeState);
const setNodeMatrixIndices = useStore(
(state) => state.setNodeMatrixIndices
);
const calculateCoordsBasedOnRotation = (
x: number,
@ -174,11 +171,11 @@ const NodeManager = (props: StateManagerProps) => {
delay?: number
) => {
setTimeout(() => {
node.matrixIndices = newNodeMatrixIndices;
setActiveNode(node);
setNodeMatrixIndices(newNodeMatrixIndices);
}, delay);
},
[setActiveNode, setNodeMatrixIndices]
[setActiveNode]
);
const dispatchObject = useCallback(

11
src/hooks/usePrevious.tsx Normal file
View file

@ -0,0 +1,11 @@
import { useEffect, useRef } from "react";
const usePrevious = <T extends unknown>(value: T): T | undefined => {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
export default usePrevious;

View file

@ -1,4 +1,3 @@
import { a } from "@react-spring/three";
import { OrbitControls } from "@react-three/drei";
import React, { Suspense, useEffect, useMemo } from "react";
import Lain from "../components/MainScene/Lain";
@ -24,18 +23,15 @@ const MainScene = () => {
return (
<perspectiveCamera position-z={3}>
<Suspense fallback={null}>
<a.group>
<Preloader />
<LevelSelection />
<Pause paused={isPaused} />
<SyncedComponentLoader paused={isPaused} shouldIntro={shouldIntro} />
<OrbitControls />
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />
<pointLight color={0x7f7f7f} position={[0, 10, 0]} intensity={1.5} />
<pointLight color={0xffffff} position={[8, 0, 0]} intensity={0.2} />
<pointLight color={0xffffff} position={[-8, 0, 0]} intensity={0.2} />
</a.group>
<Lain shouldIntro={shouldIntro} />
<Preloader />
<LevelSelection />
<Pause paused={isPaused} />
<SyncedComponentLoader paused={isPaused} shouldIntro={shouldIntro} />
<OrbitControls />
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />
<pointLight color={0x7f7f7f} position={[0, 10, 0]} intensity={1.5} />
<pointLight color={0xffffff} position={[8, 0, 0]} intensity={0.2} />
<pointLight color={0xffffff} position={[-8, 0, 0]} intensity={0.2} />
</Suspense>
</perspectiveCamera>
);

View file

@ -44,12 +44,6 @@ type State = {
hudActive: boolean;
activeNode: NodeDataType;
activeNodeMatrixIndices: {
matrixIdx: number;
rowIdx: number;
colIdx: number;
};
activeNodePos: number[];
activeNodeRot: number[];
activeNodeState: {
@ -212,8 +206,8 @@ export const useStore = create(
"2": "quiet",
"3": "hallucination",
},
matrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
},
activeNodeMatrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
activeNodePos: [0, 0, 0],
activeNodeRot: [0, 0, 0],
activeNodeState: {
@ -333,11 +327,6 @@ export const useStore = create(
// node setters
setNode: (to: NodeDataType) => set(() => ({ activeNode: to })),
setNodeMatrixIndices: (to: {
matrixIdx: number;
rowIdx: number;
colIdx: number;
}) => set(() => ({ activeNodeMatrixIndices: to })),
setNodePos: (to: number[]) => set(() => ({ activeNodePos: to })),
setNodeRot: (to: number[]) => set(() => ({ activeNodeRot: to })),
setNodeState: (
@ -511,5 +500,4 @@ export const useSiteSaveStore = create(
)
);
export const getMainSceneContext = () =>
useStore.getState().activeNode;
export const getMainSceneContext = () => useStore.getState().activeNode;