mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 15:09:05 +00:00
got rid of middlering manager, fixed some bugs, got more to go.
This commit is contained in:
parent
0258738867
commit
acceaa149a
19 changed files with 569 additions and 569 deletions
|
@ -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 (
|
||||
<>
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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]}
|
||||
>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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!} />
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
|
@ -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,
|
||||
|
|
22
src/core/utils/filterInvisibleNodes.ts
Normal file
22
src/core/utils/filterInvisibleNodes.ts
Normal 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;
|
|
@ -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} />
|
||||
|
|
62
src/store.ts
62
src/store.ts
|
@ -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 })),
|
||||
|
||||
|
|
Loading…
Reference in a new issue