got rid of middlering manager, fixed some bugs, got more to go.

This commit is contained in:
ad044 2021-01-28 22:32:29 +04:00
parent 0258738867
commit acceaa149a
19 changed files with 569 additions and 569 deletions

View file

@ -5,11 +5,7 @@ import StaticBigLetter from "../../TextRenderer/StaticBigLetter";
import { useStore } from "../../../store";
import { useLoader } from "react-three-fiber";
type PauseProps = {
paused: boolean;
};
const Pause = (props: PauseProps) => {
const Pause = () => {
const exit = useStore((state) => state.pauseExitAnimation);
const [showActiveComponent, setShowActiveComponent] = useState(false);
const [animation, setAnimation] = useState(false);
@ -58,20 +54,24 @@ const Pause = (props: PauseProps) => {
[generateSqaureGeom]
);
const subscene = useStore((state) => state.mainSubscene);
useEffect(() => {
setAnimation(false);
setIntro(true);
setShowActiveComponent(false);
if (props.paused) {
if (subscene === "pause") {
setTimeout(() => {
setAnimation(true);
}, 1000);
setTimeout(() => {
setShowActiveComponent(true);
setIntro(false);
}, 3500);
setTimeout(() => {
setAnimation(true);
}, 1000);
setTimeout(() => {
setShowActiveComponent(true);
setIntro(false);
}, 3500);
}, 3400);
}
}, [props.paused]);
}, [subscene]);
return (
<>

View file

@ -10,6 +10,7 @@ import MainSceneEventManager from "../../core/StateManagers/MainSceneEventManage
import Pause from "./PauseSubscene/Pause";
import { a } from "@react-spring/three";
import Lain from "./Lain";
import { useStore } from "../../store";
type SyncedComponentLoaderProps = {
paused: boolean;
@ -18,6 +19,7 @@ type SyncedComponentLoaderProps = {
const SyncedComponentLoader = (props: SyncedComponentLoaderProps) => {
const [introFinished, setIntroFinished] = useState(false);
const [paused, setPaused] = useState(false);
useEffect(() => {
if (!props.shouldIntro) {
@ -31,25 +33,33 @@ const SyncedComponentLoader = (props: SyncedComponentLoaderProps) => {
}, 4000);
}, [props.shouldIntro]);
const visible = useMemo(() => {
if (props.paused) {
return false;
const subscene = useStore((state) => state.mainSubscene);
useEffect(() => {
if (subscene === "pause") {
setTimeout(() => {
setPaused(true);
}, 3400);
} else {
return props.shouldIntro ? introFinished : true;
setPaused(false);
}
}, [introFinished, props.paused, props.shouldIntro]);
}, [subscene]);
const visible = useMemo(() => {
return props.shouldIntro ? introFinished : true;
}, [introFinished, props.shouldIntro]);
return (
<>
<group visible={visible}>
<group visible={visible && !paused}>
<HUD />
<YellowTextRenderer />
<YellowOrb visible={visible} />
<YellowOrb visible={visible && !paused} />
<MiddleRing />
<GrayPlanes />
</group>
<Starfield
visible={!props.paused}
visible={!paused}
shouldIntro={props.shouldIntro}
introFinished={introFinished}
/>

View file

@ -42,7 +42,8 @@ const HUD = memo(() => {
const siteRotY = useStore((state) => state.siteRot[1]);
const sitePosY = useStore((state) => state.sitePos[1]);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ siteRotY, sitePosY, subscene });
const scene = useStore((state) => state.currentScene);
const prevData = usePrevious({ siteRotY, sitePosY, subscene, scene });
// this part is imperative because it performs a lot better than having a toggleable spring.
useFrame(() => {
@ -87,67 +88,89 @@ const HUD = memo(() => {
});
useEffect(() => {
const mirror = () => {
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);
};
const unMirror = () => {
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);
};
if (activeRef.current !== undefined) {
const hud = getNodeHud(activeNodeMatrixIndices!);
if (
prevData?.siteRotY !== siteRotY ||
prevData?.sitePosY !== sitePosY ||
subscene === "level_selection"
(!(scene === "main" && prevData?.scene === "main") ||
(subscene === "site" && prevData?.subscene === "pause") ||
subscene === "pause") &&
longHudRef.current &&
bigHudRef.current &&
boringHudRef.current &&
greenTextRef.current
) {
activeRef.current = false;
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.position[0];
boringHudRef.current.position.x = hud.boring.position[0];
bigHudRef.current.position.x = hud.big.position[0];
greenTextRef.current.position.x = hud.medium_text.position[0];
} 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];
if (
prevData?.siteRotY !== siteRotY ||
prevData?.sitePosY !== sitePosY ||
subscene === "level_selection"
) {
activeRef.current = false;
} else {
const wasHidden = !activeRef.current;
activeRef.current = false;
setTimeout(
() => {
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);
if (hud.mirrored) {
mirror();
} else {
unMirror();
}
currentHudRef.current = hud;
activeRef.current = true;
}
currentHudRef.current = hud;
activeRef.current = true;
}
},
wasHidden ? 0 : 500
);
},
wasHidden ? 0 : 500
);
}
}
}
}, [
activeNodeMatrixIndices,
prevData?.scene,
prevData?.sitePosY,
prevData?.siteRotY,
prevData?.subscene,
scene,
sitePosY,
siteRotY,
subscene,

View file

@ -1,51 +1,16 @@
import React, { useMemo, useRef } from "react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import middleRingTexture from "../../../static/sprite/middle_ring_tex.png";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
import MiddleRingPart from "./MiddleRing/MiddleRingPart";
import usePrevious from "../../../hooks/usePrevious";
import lerp from "../../../core/utils/lerp";
const MiddleRing = () => {
const middleRingTex = useLoader(THREE.TextureLoader, middleRingTexture);
const pos = useStore((state) => state.middleRingPos);
const rot = useStore((state) => state.middleRingRot);
const wobbleAmp = useStore((state) => state.middleRingWobbleAmp);
const noiseAmp = useStore((state) => state.middleRingNoiseAmp);
const rotating = useStore((state) => state.middleRingRotating);
const mainRingVisible = useStore(
(state) => !state.fakeMiddleRingVisible
);
const wobbleState = useSpring({
wobbleStrength: wobbleAmp,
noiseStrength: noiseAmp,
config: { duration: 200 },
});
const posState = useSpring({
posY: pos[1],
config: { duration: 600 },
});
const rotState = useSpring({
rotX: rot[0],
rotZ: rot[2],
config: { duration: 1000 },
});
const uniforms = useMemo(
() => ({
tex: { type: "t", value: middleRingTex },
uTime: { value: 1.0 },
wobbleStrength: { value: 0.0 },
noiseAmp: { value: 0.03 },
}),
[middleRingTex]
);
const middleRingMaterialRef = useRef<THREE.ShaderMaterial>();
const middleRingRef = useRef<THREE.Object3D>();
const middleRingPartRef = useRef<THREE.Object3D>();
@ -193,11 +158,24 @@ const MiddleRing = () => {
const clock = new THREE.Clock();
const [wobbleAmp, setWobbleAmp] = useState(0);
const [noiseAmp, setNoiseAmp] = useState(0.03);
const [rotating, setRotating] = useState(true);
const [fakeRingVisible, setFakeRingVisible] = useState(false);
const noiseAmpRef = useRef(0.03);
const wobbleAmpRef = useRef(0);
useFrame(() => {
if (middleRingMaterialRef.current) {
middleRingMaterialRef.current.uniforms.uTime.value = clock.getElapsedTime();
middleRingMaterialRef.current.uniforms.wobbleStrength.value = wobbleState.wobbleStrength.get();
middleRingMaterialRef.current.uniforms.noiseAmp.value = wobbleState.noiseStrength.get();
wobbleAmpRef.current = lerp(wobbleAmpRef.current, wobbleAmp, 0.1);
noiseAmpRef.current = lerp(noiseAmpRef.current, noiseAmp, 0.1);
middleRingMaterialRef.current.uniforms.wobbleStrength.value =
wobbleAmpRef.current;
middleRingMaterialRef.current.uniforms.noiseAmp.value =
noiseAmpRef.current;
middleRingMaterialRef.current.needsUpdate = true;
}
@ -209,6 +187,198 @@ const MiddleRing = () => {
}
});
const [posState, setPos] = useSpring(() => ({
posY: -0.11,
config: { duration: 600 },
}));
const [rotState, setRot] = useSpring(() => ({
rotX: 0,
rotZ: 0,
config: { duration: 1000 },
}));
const uniforms = useMemo(
() => ({
tex: { type: "t", value: middleRingTex },
uTime: { value: 1.0 },
wobbleStrength: { value: 0.0 },
noiseAmp: { value: 0.03 },
}),
[middleRingTex]
);
const siteRotY = useStore((state) => state.siteRot[1]);
const activeLevel = useStore((state) => state.activeLevel);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ siteRotY, activeLevel, subscene });
useEffect(() => {
const rotate = (rotValues: [number, number]) => {
setTimeout(() => {
setRot({ rotZ: rotValues[0] });
}, 2300);
setTimeout(() => {
setRot({ rotZ: rotValues[1] });
}, 3500);
setTimeout(() => {
setRot({ rotZ: 0 });
}, 4500);
};
const moveDown = () => {
setTimeout(() => {
setNoiseAmp(0.06);
setRotating(false);
}, 800);
setTimeout(() => {
setPos({ posY: 1.39 });
}, 1200);
// set ring rotation on x axis to craete motion effect
setTimeout(() => {
setRot({ rotX: 0.3 });
}, 1500);
setTimeout(() => {
setPos({ posY: -0.31 });
}, 3000);
setTimeout(() => {
setPos({ posY: -0.11 });
}, 3150);
// rotate it again, set ring noise to 0
setTimeout(() => {
setRot({ rotX: -0.1 });
setNoiseAmp(0);
}, 3500);
// rotate it back AGAIN (holy fuk psx game)
setTimeout(() => {
setRot({ rotX: 0.05 });
}, 4500);
// reset value, set noise to 0
setTimeout(() => {
setRot({ rotX: 0, rotZ: 0 });
setRotating(true);
}, 4800);
// enable noise again in about 11-12 secs
setTimeout(() => {
setNoiseAmp(0.03);
}, 11600);
};
const moveUp = () => {
// change noise to 0, make the ring bend downwards
setTimeout(() => {
setNoiseAmp(0);
setWobbleAmp(0.2);
}, 300);
// disable rotation of the ring
setTimeout(() => {
setRotating(false);
}, 700);
// make the ring bend upwards
setTimeout(() => {
setWobbleAmp(-0.3);
// the middle ring stays in place, therefore we animate it
// in the same direction as the site, creating that illusion.
setPos({ posY: -1.39 });
}, 1200);
// reset the ring bend, set the rotation to slightly curve
// to replicate a motion effect (since its moving upwards)
// and enable rotation again
setTimeout(() => {
setWobbleAmp(0);
setRot({ rotX: -0.2 });
setRotating(true);
}, 1500);
setTimeout(() => {
setPos({ posY: 0.09 });
}, 2900);
// reset the rotation value to 0
setTimeout(() => {
setRot({ rotX: 0, rotZ: 0 });
setPos({ posY: -0.11 });
}, 3150);
// enable noise again in about 8~ secs
setTimeout(() => {
setNoiseAmp(0.03);
}, 7800);
};
const pause = () => {
setPos({ posY: 0.5 });
setTimeout(() => {
setFakeRingVisible(true);
}, 600);
setTimeout(() => {
// move the hidden (main) ring below, cuz when the pause exists it needs to jump back up
// instead of reappearing
setPos({ posY: -2.5 });
}, 1100);
setTimeout(() => {
setFakeRingVisible(false);
}, 3800);
};
const unpause = () => {
setTimeout(() => {
setRot({ rotX: -0.4 });
setRotating(true);
}, 300);
setTimeout(() => {
setPos({ posY: -0.4 });
}, 700);
// reset the rotation value to 0
setTimeout(() => {
setRot({ rotZ: 0, rotX: 0 });
setPos({ posY: -0.11 });
}, 950);
};
if (prevData?.siteRotY !== undefined && prevData?.siteRotY !== siteRotY) {
rotate(prevData?.siteRotY > siteRotY ? [-0.07, 0.03] : [0.07, -0.03]);
} else if (
prevData?.activeLevel !== undefined &&
prevData.activeLevel !== activeLevel
) {
if (prevData?.activeLevel > activeLevel) {
moveDown();
} else if (prevData?.activeLevel < activeLevel) {
moveUp();
}
} else if (subscene === "pause") {
pause();
} else if (subscene === "site" && prevData?.subscene === "pause") {
unpause();
}
}, [
activeLevel,
prevData?.activeLevel,
prevData?.siteRotY,
prevData?.subscene,
setPos,
setRot,
siteRotY,
subscene,
]);
return (
<a.group rotation-z={rotState.rotZ}>
<a.mesh
@ -217,7 +387,7 @@ const MiddleRing = () => {
ref={middleRingRef}
rotation={[0, 0.9, 0]}
rotation-x={rotState.rotX}
visible={mainRingVisible}
visible={!fakeRingVisible}
>
<cylinderBufferGeometry
args={[0.75, 0.75, 0.027, 64, 64, true]}
@ -234,7 +404,7 @@ const MiddleRing = () => {
/>
</a.mesh>
{!mainRingVisible && (
{fakeRingVisible && (
<group
rotation={[0, 0.9, 0]}
ref={middleRingPartRef}

View file

@ -18,28 +18,45 @@ const MiddleRingPart = (props: MiddleRingPartProps) => {
return middleRingTex;
}, [middleRingTex]);
const [{ posX, posZ }, set] = useSpring(() => ({
posX:
props.position[0] /
useStore.getState().middleRingPartSeparatorVal,
posZ:
props.position[2] /
useStore.getState().middleRingPartSeparatorVal,
const [posState, setPos] = useSpring(() => ({
posX: props.position[0],
posZ: props.position[2],
config: { duration: 600 },
}));
const subscene = useStore((state) => state.mainSubscene);
useEffect(() => {
useStore.subscribe(set, (state) => ({
posX: props.position[0] / state.middleRingPartSeparatorVal,
posZ: props.position[2] / state.middleRingPartSeparatorVal,
}));
}, [props.position, set]);
if (subscene === "pause") {
const posX = props.position[0];
const posZ = props.position[2];
setTimeout(() => {
setPos({ posX: posX / 0.9, posZ: posZ / 0.9 });
}, 500);
setTimeout(() => {
setPos({ posX: posX, posZ: posZ });
}, 900);
setTimeout(() => {
setPos({ posX: posX / 0.9, posZ: posZ / 0.9 });
}, 1300);
setTimeout(() => {
setPos({ posX: posX, posZ: posZ });
}, 1700);
setTimeout(() => {
setPos({ posX: posX / 0.2, posZ: posZ / 0.2 });
}, 2500);
setTimeout(() => {
setPos({ posX: posX, posZ: posZ });
}, 3200);
}
}, [props.position, setPos, subscene]);
return (
<a.group
position-x={posX}
position-z={posZ}
position-x={posState.posX}
position-z={posState.posZ}
position-y={props.position[1]}
rotation={props.rotation as [number, number, number]}
>

View file

@ -1,4 +1,4 @@
import React, { Suspense, useMemo, useRef } from "react";
import React, { Suspense, useEffect, useMemo, useRef } from "react";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
import ActiveLevelNodes from "./Site/ActiveLevelNodes";
@ -8,6 +8,9 @@ import InactiveLevelNodes from "./Site/InactiveLevelNodes";
import { useFrame } from "react-three-fiber";
import * as THREE from "three";
import lerp from "../../../core/utils/lerp";
import filterInvisibleNodes from "../../../core/utils/filterInvisibleNodes";
import site_a from "../../../resources/site_a.json";
import site_b from "../../../resources/site_b.json";
export type NodeDataType = {
id: string;
@ -68,16 +71,32 @@ const Site = (props: SiteProps) => {
}
});
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);
const visibleNodes = useMemo(
() =>
filterInvisibleNodes(currentSite === "a" ? site_a : site_b, gameProgress),
[currentSite, gameProgress]
);
return (
<Suspense fallback={null}>
<a.group ref={introWrapperRef} position-z={-10} rotation-x={Math.PI / 2}>
<a.group ref={introWrapperRef}>
<a.group rotation-x={siteState.siteRotX}>
<a.group
rotation-y={siteState.siteRotY}
position-y={siteState.sitePosY}
>
<ActiveLevelNodes />
<InactiveLevelNodes />
{/*<InactiveLevelNodes />*/}
<NodeAnimations />
<Rings
activateAllRings={props.shouldIntro ? props.introFinished : true}

View file

@ -1,30 +1,46 @@
import React, { useMemo, memo } from "react";
import React, { memo, useEffect, useState } from "react";
import Node from "./Node";
import node_positions from "../../../../resources/node_positions.json";
import { useStore } from "../../../../store";
import { isNodeVisible } from "../../../../core/nodeSelector";
import site_a from "../../../../resources/site_a.json";
import site_b from "../../../../resources/site_b.json";
import { NodeDataType } from "../Site";
import { NodeDataType, SiteType } from "../Site";
import usePrevious from "../../../../hooks/usePrevious";
const ActiveLevelNodes = memo(() => {
type ActiveLevelNodesProps = {
visibleNodes: any;
};
const ActiveLevelNodes = memo((props: ActiveLevelNodesProps) => {
const activeNodeId = useStore((state) => state.activeNode.id);
const gameProgress = useStore((state) => state.gameProgress);
const currentSite = useStore((state) => state.activeSite);
const siteData = useMemo(() => (currentSite === "a" ? site_a : site_b), [
currentSite,
]);
const activeLevel = useStore((state) => state.activeLevel);
const prevData = usePrevious({ activeLevel });
const visibleNodes = useMemo(
() => siteData[activeLevel as keyof typeof siteData],
[activeLevel, siteData]
const [visibleNodes, setVisibleNodes] = useState(
props.visibleNodes[activeLevel]
);
useEffect(() => {
const siteData = currentSite === "a" ? site_a : site_b;
if (
prevData?.activeLevel !== activeLevel &&
prevData?.activeLevel !== undefined
) {
const prevLevel = parseInt(prevData?.activeLevel);
const newLevel = parseInt(activeLevel);
if (prevLevel - 1 === newLevel || prevLevel + 1 === newLevel) {
setVisibleNodes(siteData[activeLevel as keyof typeof siteData]);
} else {
setTimeout(() => {
setVisibleNodes(siteData[activeLevel as keyof typeof siteData]);
}, 1500);
}
}
}, [activeLevel, currentSite, gameProgress, prevData?.activeLevel]);
return (
<>
{Object.values(visibleNodes).map((node: NodeDataType) => {

View file

@ -4,92 +4,106 @@ 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, { memo, useEffect, useMemo, useState } from "react";
import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
import { useStore } from "../../store";
import usePrevious from "../../hooks/usePrevious";
const BigLetter = memo(
(props: {
color?: string;
letter: string;
letterIdx: number;
xOffset?: number;
}) => {
const [color, setColor] = useState("yellow");
const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
const [color, setColor] = useState("yellow");
const tex = useMemo(
() =>
color === "orange" || props.letterIdx === 0 ? orangeFont : yellowFont,
[color, props.letterIdx]
);
const tex = useMemo(
() =>
color === "orange" || props.letterIdx === 0 ? orangeFont : yellowFont,
[color, props.letterIdx]
);
const colorTexture: THREE.Texture = useLoader(THREE.TextureLoader, tex);
const colorTexture: THREE.Texture = useLoader(THREE.TextureLoader, tex);
const lineYOffset = useMemo(() => {
const lineOne = "ABCDEFGHIJKLMNOPQ";
const lineTwo = "RSTUVWXYZ01234567";
const lineThree = "89abcdefghijklmnopqrs";
const lineYOffset = useMemo(() => {
const lineOne = "ABCDEFGHIJKLMNOPQ";
const lineTwo = "RSTUVWXYZ01234567";
const lineThree = "89abcdefghijklmnopqrs";
let lineNum: number;
if (props.letter === " ") {
lineNum = 5;
let lineNum: number;
if (props.letter === " ") {
lineNum = 5;
} else {
if (lineOne.includes(props.letter)) {
lineNum = 1;
} else if (lineTwo.includes(props.letter)) {
lineNum = 2;
} else if (lineThree.includes(props.letter)) {
lineNum = 3;
} else {
if (lineOne.includes(props.letter)) {
lineNum = 1;
} else if (lineTwo.includes(props.letter)) {
lineNum = 2;
} else if (lineThree.includes(props.letter)) {
lineNum = 3;
} else {
lineNum = 4;
}
lineNum = 4;
}
}
const offsets = {
1: 0.884,
2: 0.765,
3: 0.648,
4: 0.47,
5: 1,
};
return offsets[lineNum as keyof typeof offsets];
}, [props.letter]);
const offsets = {
1: 0.884,
2: 0.765,
3: 0.648,
4: 0.47,
5: 1,
};
return offsets[lineNum as keyof typeof offsets];
}, [props.letter]);
const letterData = useMemo(
() =>
orange_font_json.glyphs[
props.letter as keyof typeof orange_font_json.glyphs
const letterData = useMemo(
() =>
orange_font_json.glyphs[
props.letter as keyof typeof orange_font_json.glyphs
],
[props.letter]
);
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 + lineYOffset - letterData[4] / 136;
uvAttribute.setXY(i, u, v);
}
return geometry;
}, [letterData, lineYOffset]);
const activeNode = useStore((state) => state.activeNode);
const activeMediaComponent = useStore(
useCallback(
(state) =>
state.mediaComponentMatrix[state.mediaComponentMatrixIndices.sideIdx][
state.mediaComponentMatrixIndices.sideIdx === 0
? state.mediaComponentMatrixIndices.leftSideIdx
: state.mediaComponentMatrixIndices.rightSideIdx
],
[props.letter]
);
[]
)
);
const subscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
const prevData = usePrevious({ scene, subscene });
const [lastMediaLeftComponent, setLastMediaLeftComponent] = useState("play");
const geom = useMemo(() => {
const geometry = new THREE.PlaneBufferGeometry();
const [shrinkState, set] = useSpring(() => ({
x: props.letterIdx + 0.3,
config: { duration: 200 },
}));
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 + lineYOffset - letterData[4] / 136;
uvAttribute.setXY(i, u, v);
}
return geometry;
}, [letterData, lineYOffset]);
const activeNode = useStore((state) => state.activeNode);
const subscene = useStore((state) => state.mainSubscene);
const [shrinkState, set] = useSpring(() => ({
x: props.letterIdx + 0.3,
config: { duration: 200 },
}));
useEffect(() => {
useEffect(() => {
if (
subscene === "pause" ||
(subscene === "site" && prevData?.subscene === "pause")
)
return;
if (scene === "main" && prevData?.scene === "main") {
set({ x: 0 });
if (subscene === "level_selection") {
setColor("orange");
@ -101,24 +115,45 @@ const BigLetter = memo(
setTimeout(() => {
set({ x: props.letterIdx + 0.3 });
}, 1200);
}, [activeNode, props.letterIdx, subscene, set, color]);
} else if (scene === "media") {
if (
(activeMediaComponent === "play" || activeMediaComponent === "exit") &&
activeMediaComponent !== lastMediaLeftComponent
) {
setLastMediaLeftComponent(activeMediaComponent);
set({ x: 0 });
setTimeout(() => {
set({ x: props.letterIdx + 0.3 });
}, 1200);
}
}
}, [
activeNode,
props.letterIdx,
subscene,
set,
color,
scene,
activeMediaComponent,
lastMediaLeftComponent,
prevData?.scene,
]);
return (
<a.mesh
position-x={shrinkState.x}
position-y={-letterData[4] / 12.5}
scale={[1, 1, 0]}
geometry={geom}
renderOrder={props.letterIdx === 0 ? 11 : 10}
>
<meshBasicMaterial
map={colorTexture}
attach="material"
transparent={true}
/>
</a.mesh>
);
}
);
return (
<a.mesh
position-x={shrinkState.x}
position-y={-letterData[4] / 12.5}
scale={[1, 1, 0]}
geometry={geom}
renderOrder={props.letterIdx === 0 ? 11 : 10}
>
<meshBasicMaterial
map={colorTexture}
attach="material"
transparent={true}
/>
</a.mesh>
);
});
export default BigLetter;

View file

@ -7,7 +7,6 @@ const MediaYellowTextAnimator = memo(() => {
const [lastLeftComponent, setLastLeftComponent] = useState("play");
const [textArr, setTextArr] = useState("Play".split(""));
const [posY, setPosY] = useState(0.05);
const [xOffset, setXOffset] = useState(0);
const trail = useTrail(textArr.length, {
posY: posY,
@ -32,8 +31,6 @@ const MediaYellowTextAnimator = memo(() => {
activeMediaComponent !== lastLeftComponent
) {
setLastLeftComponent(activeMediaComponent);
setXOffset(-1);
setTimeout(() => {
if (activeMediaComponent === "play") {
setPosY(0.05);
@ -50,10 +47,6 @@ const MediaYellowTextAnimator = memo(() => {
).split("")
);
}, 1000);
setTimeout(() => {
setXOffset(0);
}, 1200);
}
}, [activeMediaComponent, lastLeftComponent]);
@ -73,13 +66,7 @@ const MediaYellowTextAnimator = memo(() => {
position-z={-8.7}
scale={[0.04, 0.06, 0.04]}
>
<BigLetter
color={"yellow"}
xOffset={xOffset}
letter={textArr[idx]}
letterIdx={idx}
key={idx}
/>
<BigLetter letter={textArr[idx]} letterIdx={idx} key={idx} />
</a.group>
))}
</group>

View file

@ -21,25 +21,23 @@ const YellowTextRenderer = (props: { visible?: boolean }) => {
}));
useEffect(() => {
if (prevData?.subscene !== "pause") {
const hud = getNodeHud(activeNode.matrixIndices!);
if (subscene === "level_selection") {
setTimeout(() => {
set({ posX: -0.02, posY: 0.005 });
}, 400);
const hud = getNodeHud(activeNode.matrixIndices!);
if (subscene === "level_selection") {
setTimeout(() => {
set({ posX: -0.02, posY: 0.005 });
}, 400);
setTimeout(() => {
setText("JumpTo".split(""));
}, 1000);
} else {
setTimeout(() => {
set({ posX: hud.big_text[0], posY: hud.big_text[1] });
}, 400);
setTimeout(() => {
setText("JumpTo".split(""));
}, 1000);
} else {
setTimeout(() => {
set({ posX: hud.big_text[0], posY: hud.big_text[1] });
}, 400);
setTimeout(() => {
setText(activeNode.node_name.split(""));
}, 1000);
}
setTimeout(() => {
setText(activeNode.node_name.split(""));
}, 1000);
}
}, [activeNode, prevData?.subscene, set, subscene]);

View file

@ -25,7 +25,6 @@ const GameLoader = (props: StateManagerProps) => {
const setActiveNode = useStore((state) => state.setNode);
// node hud setter
const setHud = useStore((state) => state.setHud);
const changeSite = useCallback((site: string) => {
// load new site

View file

@ -27,7 +27,7 @@ const SubsceneManager = (props: StateManagerProps) => {
return {
action: setMainSubscene,
value: "pause",
delay: 3400,
delay: 0,
};
case "pause_exit_select":
case "pause_change_select":

View file

@ -5,7 +5,6 @@ import { getKeyCodeAssociation } from "../utils/keyPressUtils";
import NodeManager from "./MainSceneManagers/NodeManager";
import SiteManager from "./MainSceneManagers/SiteManager";
import LainManager from "./MainSceneManagers/LainManager";
import MiddleRingManager from "./MainSceneManagers/MiddleRingManager";
import SceneManager from "./GameManagers/SceneManager";
import LevelManager from "./MainSceneManagers/LevelManager";
import LevelSelectionManager from "./MainSceneManagers/LevelSelectionManager";
@ -139,7 +138,6 @@ const MainSceneEventManager = (props: MainSceneEventManagerProps) => {
<NodeManager eventState={eventState!} />
<SiteManager eventState={eventState!} />
<LainManager eventState={eventState!} />
<MiddleRingManager eventState={eventState!} />
<SceneManager eventState={eventState!} />
<LevelManager eventState={eventState!} />
<LevelSelectionManager eventState={eventState!} />

View file

@ -9,19 +9,14 @@ const LevelManager = (props: StateManagerProps) => {
(eventState: { event: string; level: string }) => {
switch (eventState.event) {
case "site_up":
case "select_level_down":
case "select_level_up":
case "site_down":
return {
action: setActiveLevel,
value: eventState.level,
delay: 0,
};
case "select_level_down":
case "select_level_up":
return {
action: setActiveLevel,
value: eventState.level,
delay: 1500,
};
}
},
[setActiveLevel]

View file

@ -1,216 +0,0 @@
import { useCallback, useEffect } from "react";
import { useStore } from "../../../store";
const MiddleRingManager = (props: any) => {
const setRot = useStore((state) => state.setMiddleRingRot);
const setPos = useStore((state) => state.setMiddleRingPos);
const setRotating = useStore((state) => state.setMiddleRingRotating);
const setNoiseAmp = useStore((state) => state.setMiddleRingNoiseAmp);
const setWobbleAmp = useStore(
(state) => state.setMiddleRingWobbleAmp
);
const setFakeRingVisible = useStore(
(state) => state.setFakeMiddleRingVisible
);
const setPartSeparatorVal = useStore(
(state) => state.setMiddleRingPartSeparatorVal
);
const rotate = useCallback(
(direction: string) => {
const rotValues = direction === "right" ? [-0.07, 0.03] : [0.07, -0.03];
setTimeout(() => {
setRot([0, 0, rotValues[0]]);
}, 2300);
setTimeout(() => {
setRot([0, 0, rotValues[1]]);
}, 3500);
setTimeout(() => {
setRot([0, 0, 0]);
}, 4500);
},
[setRot]
);
const moveDown = useCallback(() => {
// make noise appear again
// disable rotation of the ring
setTimeout(() => {
setNoiseAmp(0.06);
setRotating(false);
}, 800);
setTimeout(() => {
setPos([0, 1.39, 0]);
}, 1300);
// set ring rotation on x axis to craete motion effect
setTimeout(() => {
setRot([0.3, 0, 0]);
}, 1500);
setTimeout(() => {
setPos([0, -0.31, 0]);
}, 3000);
setTimeout(() => {
setPos([0, -0.11, 0]);
}, 3150);
// rotate it again, set ring noise to 0
setTimeout(() => {
setRot([-0.1, 0, 0]);
setNoiseAmp(0);
}, 3500);
// rotate it back AGAIN (holy fuk psx game)
setTimeout(() => {
setRot([0.05, 0, 0]);
}, 4500);
// reset value, set noise to 0
setTimeout(() => {
setRot([0, 0, 0]);
setRotating(true);
}, 4800);
// enable noise again in about 11-12 secs
setTimeout(() => {
setNoiseAmp(0.03);
}, 11600);
}, [setNoiseAmp, setPos, setRot, setRotating]);
const moveUp = useCallback(() => {
// change noise to 0, make the ring bend downwards
setTimeout(() => {
setNoiseAmp(0);
setWobbleAmp(0.2);
}, 300);
// disable rotation of the ring
setTimeout(() => {
setRotating(false);
}, 700);
// make the ring bend upwards
setTimeout(() => {
setWobbleAmp(-0.3);
// the middle ring stays in place, therefore we animate it
// in the same direction as the site, creating that illusion.
setPos([0, -1.39, 0]);
}, 1300);
// reset the ring bend, set the rotation to slightly curve
// to replicate a motion effect (since its moving upwards)
// and enable rotation again
setTimeout(() => {
setWobbleAmp(0);
setRot([-0.2, 0, 0]);
setRotating(true);
}, 1500);
setTimeout(() => {
setPos([0, 0.09, 0]);
}, 2900);
// reset the rotation value to 0
setTimeout(() => {
setRot([0, 0, 0]);
setPos([0, -0.11, 0]);
}, 3150);
// enable noise again in about 8~ secs
setTimeout(() => {
setNoiseAmp(0.03);
}, 7800);
}, [setNoiseAmp, setPos, setRot, setRotating, setWobbleAmp]);
const animatePause = useCallback(() => {
setPos([0, 0.5, 0]);
setTimeout(() => {
setFakeRingVisible(true);
}, 600);
setTimeout(() => {
setPartSeparatorVal(0.9);
// move the hidden (main) ring below, cuz when the pause exists it needs to jump back up
// instead of reappearing
setPos([0, -2.5, 0]);
}, 1100);
setTimeout(() => {
setPartSeparatorVal(1);
}, 1500);
setTimeout(() => {
setPartSeparatorVal(0.9);
}, 1900);
setTimeout(() => {
setPartSeparatorVal(1);
}, 2300);
setTimeout(() => {
setPartSeparatorVal(0.2);
}, 3100);
setTimeout(() => {
setFakeRingVisible(false);
setPartSeparatorVal(1);
}, 3800);
}, [setFakeRingVisible, setPartSeparatorVal, setPos]);
const animateUnpause = useCallback(() => {
setTimeout(() => {
setTimeout(() => {
setRot([-0.4, 0, 0]);
setRotating(true);
}, 500);
setTimeout(() => {
setPos([0, 0.13, 0]);
}, 900);
// reset the rotation value to 0
setTimeout(() => {
setRot([0, 0, 0]);
setPos([0, -0.11, 0]);
}, 1150);
}, 1000);
}, [setPos, setRot, setRotating]);
const dispatchObject = useCallback(
(eventState: { event: string }) => {
switch (eventState.event) {
case "site_up":
case "select_level_up":
return { action: moveUp };
case "select_level_down":
case "site_down":
return { action: moveDown };
case "site_left":
return { action: rotate, value: ["left"] };
case "site_right":
return { action: rotate, value: ["right"] };
case "pause_game":
return { action: animatePause };
case "pause_exit_select":
case "pause_change_select":
return { action: animateUnpause };
}
},
[animatePause, animateUnpause, moveDown, moveUp, rotate]
);
useEffect(() => {
if (props.eventState) {
const dispatchedObject = dispatchObject(props.eventState);
if (dispatchedObject) {
dispatchedObject.action.apply(null, dispatchedObject.value as any);
}
}
}, [dispatchObject, props.eventState]);
return null;
};
export default MiddleRingManager;

View file

@ -11,9 +11,7 @@ const MediaComponentManager = (props: StateManagerProps) => {
const setRightComponentMatrixIdx = useStore(
(state) => state.setMediaRightComponentMatrixIdx
);
const setWordPosStateIdx = useStore(
(state) => state.setMediaWordPosStateIdx
);
const setWordPosStateIdx = useStore((state) => state.setMediaWordPosStateIdx);
const resetComponentMatrixIndices = useStore(
(state) => state.resetMediaComponentMatrixIndices
@ -45,7 +43,9 @@ const MediaComponentManager = (props: StateManagerProps) => {
mediaElement.pause();
mediaElement.currentTime = 0;
}
}, []);
resetComponentMatrixIndices();
resetWordPosStateIdx();
}, [resetComponentMatrixIndices, resetWordPosStateIdx]);
const updateRightSide = useCallback(
(newRightSideComponentIdx: 0 | 1 | 2, newWordPosStateIdx: number) => {
@ -55,11 +55,6 @@ const MediaComponentManager = (props: StateManagerProps) => {
[setRightComponentMatrixIdx, setWordPosStateIdx]
);
const resetMediaState = useCallback(() => {
resetComponentMatrixIndices();
resetWordPosStateIdx();
}, [resetComponentMatrixIndices, resetWordPosStateIdx]);
const dispatchObject = useCallback(
(eventState: {
event: string;
@ -88,10 +83,6 @@ const MediaComponentManager = (props: StateManagerProps) => {
return {
action: toggleSide,
};
case "throw_node_media":
return {
action: resetMediaState,
};
case "media_play_select":
return { action: playMedia };
case "media_exit_select":
@ -101,7 +92,6 @@ const MediaComponentManager = (props: StateManagerProps) => {
[
exitMedia,
playMedia,
resetMediaState,
setLeftComponentMatrixIdx,
toggleSide,
updateRightSide,

View file

@ -0,0 +1,22 @@
import {
NodeDataType,
SiteType,
} from "../../components/MainScene/SyncedComponents/Site";
import game_progress from "../../resources/initial_progress.json";
import { isNodeVisible } from "../nodeSelector";
const filterInvisibleNodes = (
siteData: SiteType,
gameProgress: typeof game_progress
) => {
const visibleNodes: NodeDataType[] = [];
Object.values(siteData).forEach((level) => {
Object.values(level).forEach((node) => {
if (isNodeVisible(node, gameProgress)) visibleNodes.push(node);
});
});
return visibleNodes;
};
export default filterInvisibleNodes;

View file

@ -1,6 +1,5 @@
import { OrbitControls } from "@react-three/drei";
import React, { Suspense, useEffect, useMemo } from "react";
import Lain from "../components/MainScene/Lain";
import Preloader from "../components/Preloader";
import { useStore } from "../store";
import Pause from "../components/MainScene/PauseSubscene/Pause";
@ -25,7 +24,7 @@ const MainScene = () => {
<Suspense fallback={null}>
<Preloader />
<LevelSelection />
<Pause paused={isPaused} />
<Pause />
<SyncedComponentLoader paused={isPaused} shouldIntro={shouldIntro} />
<OrbitControls />
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />

View file

@ -34,9 +34,6 @@ type State = {
intro: boolean;
hud: HUDType;
hudActive: boolean;
activeNode: NodeDataType;
activeNodePos: number[];
activeNodeRot: number[];
@ -55,15 +52,6 @@ type State = {
siteRot: number[];
sitePos: number[];
// middle ring
middleRingPos: number[];
middleRingRot: number[];
middleRingWobbleAmp: number;
middleRingNoiseAmp: number;
middleRingPartSeparatorVal: number;
middleRingRotating: boolean;
fakeMiddleRingVisible: boolean;
// level
activeLevel: string;
@ -142,29 +130,6 @@ export const useStore = create(
// whether or not to play the intro anim
intro: true,
// hud
hud: {
mirrored: 0,
long: {
position: [-0.45, 0.15, -8.6],
initial_position: [-1.45, 0.15, -8.6],
},
boring: {
position: [0.48, 0.174, -8.6],
initial_position: [1.48, 0.174, -8.6],
},
big: {
position: [0.36, 0.13, -8.6],
initial_position: [1.36, 0.13, -8.6],
},
big_text: [-0.35, 0.23, -8.7],
medium_text: {
position: [0.18, 0.16, -8.7],
initial_position: [1.18, 0.16, -8.7],
},
},
hudActive: true,
// nodes
activeNode: {
id: "0422",
@ -212,15 +177,6 @@ export const useStore = create(
siteRot: [0, 0, 0],
sitePos: [0, 0, 0],
// middle ring
middleRingPos: [0, -0.11, 0],
middleRingRot: [0, 0, 0],
middleRingWobbleAmp: 0,
middleRingNoiseAmp: 0,
middleRingPartSeparatorVal: 1,
middleRingRotating: true,
fakeMiddleRingVisible: false,
// level
activeLevel: "04",
@ -300,10 +256,6 @@ export const useStore = create(
// intro setters
setIntro: (to: boolean) => set(() => ({ intro: to })),
// hud setters
setHud: (to: HUDType) => set(() => ({ hud: to })),
toggleHudActive: () => set((state) => ({ hudActive: !state.hudActive })),
// node setters
setNode: (to: NodeDataType) => set(() => ({ activeNode: to })),
setNodePos: (to: number[]) => set(() => ({ activeNodePos: to })),
@ -330,20 +282,6 @@ export const useStore = create(
}),
setSitePos: (to: number[]) => set(() => ({ sitePos: to })),
// middle ring setters
setMiddleRingPos: (to: number[]) => set(() => ({ middleRingPos: to })),
setMiddleRingRot: (to: number[]) => set(() => ({ middleRingRot: to })),
setMiddleRingWobbleAmp: (to: number) =>
set(() => ({ middleRingWobbleAmp: to })),
setMiddleRingNoiseAmp: (to: number) =>
set(() => ({ middleRingNoiseAmp: to })),
setMiddleRingPartSeparatorVal: (to: number) =>
set(() => ({ middleRingPartSeparatorVal: to })),
setMiddleRingRotating: (to: boolean) =>
set(() => ({ middleRingRotating: to })),
setFakeMiddleRingVisible: (to: boolean) =>
set(() => ({ fakeMiddleRingVisible: to })),
// level setters
setActiveLevel: (to: string) => set(() => ({ activeLevel: to })),