word sleection animation

This commit is contained in:
ad044 2021-02-03 22:54:58 +04:00
parent 1f3126e1b9
commit dc545ba522
12 changed files with 129 additions and 121 deletions

View file

@ -1,4 +1,4 @@
import React, { Suspense, useEffect, useMemo, useState } from "react";
import React, { Suspense, useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainSingularAnimator } from "three-plain-animator/lib/plain-singular-animator";
@ -66,6 +66,7 @@ export const LainConstructor = (props: LainConstructorProps) => {
attach="material"
map={lainSpriteTexture}
alphaTest={0.01}
color={0xffffff}
/>
);
};
@ -355,6 +356,8 @@ type LainProps = {
const Lain = (props: LainProps) => {
const lainMoveState = useStore((state) => state.lainMoveState);
const wordSelected = useStore((state) => state.wordSelected);
const lainAnimationDispatch = useMemo(() => {
const anims = {
standing: <LainStanding />,
@ -401,9 +404,27 @@ const Lain = (props: LainProps) => {
return props.shouldIntro ? introFinished : true;
}, [introFinished, props.shouldIntro]);
const lainRef = useRef<THREE.Sprite>();
const glowColor = useMemo(() => new THREE.Color(2, 2, 2), []);
const regularColor = useMemo(() => new THREE.Color(1, 1, 1), []);
useEffect(() => {
if (wordSelected)
setTimeout(() => {
if (lainRef.current) lainRef.current.material.color = glowColor;
}, 3100);
}, [glowColor, wordSelected]);
useFrame(() => {
if (lainRef.current) {
lainRef.current.material.color.lerp(regularColor, 0.07);
}
});
return (
<Suspense fallback={null}>
<sprite scale={[4.5, 4.5, 4.5]} position={[0, -0.15, 0]}>
<sprite scale={[4.5, 4.5, 4.5]} position={[0, -0.15, 0]} ref={lainRef}>
{stopIntroAnim ? lainAnimationDispatch : <LainIntro />}
</sprite>
</Suspense>

View file

@ -1,69 +0,0 @@
import React, { useEffect, useMemo, useState } from "react";
import HUD from "./SyncedComponents/HUD";
import YellowTextRenderer from "../TextRenderer/YellowTextRenderer";
import YellowOrb from "./SyncedComponents/YellowOrb";
import GrayPlanes from "./SyncedComponents/GrayPlanes";
import Starfield from "./SyncedComponents/Starfield";
import Site from "./SyncedComponents/Site";
import MiddleRing from "./SyncedComponents/MiddleRing";
import Lain from "./Lain";
import { useStore } from "../../store";
type SyncedComponentLoaderProps = {
paused: boolean;
shouldIntro: boolean;
};
const SyncedComponentLoader = (props: SyncedComponentLoaderProps) => {
const [introFinished, setIntroFinished] = useState(false);
const [paused, setPaused] = useState(false);
useEffect(() => {
if (!props.shouldIntro) {
document.getElementsByTagName("canvas")[0].className =
"main-scene-background";
}
setTimeout(() => {
setIntroFinished(true);
document.getElementsByTagName("canvas")[0].className =
"main-scene-background";
}, 4000);
}, [props.shouldIntro]);
const subscene = useStore((state) => state.mainSubscene);
useEffect(() => {
if (subscene === "pause") {
setTimeout(() => {
setPaused(true);
}, 3400);
} else {
setPaused(false);
}
}, [subscene]);
const visible = useMemo(() => {
return props.shouldIntro ? introFinished : true;
}, [introFinished, props.shouldIntro]);
return (
<>
<group visible={visible && !paused}>
<HUD />
<YellowTextRenderer />
<YellowOrb visible={visible && !paused} />
<MiddleRing />
<GrayPlanes />
</group>
<Starfield
visible={!paused}
shouldIntro={props.shouldIntro}
introFinished={introFinished}
/>
<Site shouldIntro={props.shouldIntro} introFinished={introFinished} />
<Lain shouldIntro={props.shouldIntro} />
</>
);
};
export default SyncedComponentLoader;

View file

@ -158,6 +158,8 @@ const MiddleRing = () => {
const clock = new THREE.Clock();
const wordSelected = useStore((state) => state.wordSelected);
const [wobbleAmp, setWobbleAmp] = useState(0);
const [noiseAmp, setNoiseAmp] = useState(0.03);
const [rotating, setRotating] = useState(true);
@ -352,6 +354,16 @@ const MiddleRing = () => {
}, 950);
};
const afterWordSelection = () => {
setRotating(true);
setRot({ rotX: -0.4 });
// reset the rotation value to 0
setTimeout(() => {
setRot({ rotZ: 0, rotX: 0 });
}, 3100);
};
if (prevData?.siteRotY !== undefined && prevData?.siteRotY !== siteRotY) {
rotate(prevData?.siteRotY > siteRotY ? [-0.07, 0.03] : [0.07, -0.03]);
} else if (
@ -367,6 +379,8 @@ const MiddleRing = () => {
pause();
} else if (subscene === "site" && prevData?.subscene === "pause") {
unpause();
} else if (wordSelected) {
afterWordSelection();
}
}, [
activeLevel,
@ -377,6 +391,7 @@ const MiddleRing = () => {
setRot,
siteRotY,
subscene,
wordSelected,
]);
return (

View file

@ -10,8 +10,8 @@ import * as THREE from "three";
import site_a from "../../../resources/site_a.json";
import site_b from "../../../resources/site_b.json";
import level_y_values from "../../../resources/level_y_values.json";
import usePrevious from "../../../hooks/usePrevious";
import { filterInvisibleNodes } from "../../../utils/node-utils";
import usePrevious from "../../../hooks/usePrevious";
export type NodeDataType = {
id: string;
@ -48,33 +48,34 @@ type SiteProps = {
};
const Site = (props: SiteProps) => {
const activeLevel = useStore((state) => state.activeLevel);
const wordSelected = useStore((state) => state.wordSelected);
const [state, setState] = useSpring(() => ({
posY: -level_y_values[
useStore.getState().activeLevel as keyof typeof level_y_values
],
rotX: useStore.getState().siteRot[0],
rotY: useStore.getState().siteRot[1],
const [rotState, setRot] = useSpring(() => ({
x: wordSelected ? 0 : useStore.getState().siteRot[0],
y: wordSelected ? 0 : useStore.getState().siteRot[1],
config: { duration: 1200 },
}));
const [posState, setPos] = useSpring(() => ({
y: wordSelected
? 0
: -level_y_values[
useStore.getState().activeLevel as keyof typeof level_y_values
],
delay: 1300,
config: { duration: 1200 },
}));
useEffect(() => {
setTimeout(() => {
setState({
posY: -level_y_values[activeLevel as keyof typeof level_y_values],
});
}, 1200);
}, [activeLevel, setState]);
useEffect(() => {
useStore.subscribe(setState, (state) => {
return {
rotX: state.siteRot[0],
rotY: state.siteRot[1],
};
});
}, [setState]);
useStore.subscribe(setRot, (state) => ({
x: state.siteRot[0],
y: state.siteRot[1],
}));
useStore.subscribe(setPos, (state) => ({
y: -level_y_values[state.activeLevel as keyof typeof level_y_values],
delay: 1300,
}));
}, [setPos, setRot]);
const introWrapperRef = useRef<THREE.Object3D>();
@ -110,8 +111,8 @@ const Site = (props: SiteProps) => {
return (
<Suspense fallback={null}>
<a.group ref={introWrapperRef}>
<a.group rotation-x={state.rotX}>
<a.group rotation-y={state.rotY} position-y={state.posY}>
<a.group rotation-x={rotState.x}>
<a.group rotation-y={rotState.y} position-y={posState.y}>
<ActiveLevelNodes visibleNodes={visibleNodes} />
<InactiveLevelNodes visibleNodes={visibleNodes} />
<Rings

View file

@ -2,7 +2,6 @@ import React, { useEffect, useState, memo } from "react";
import Star from "./Starfield/Star";
type StarfieldProps = {
visible: boolean;
shouldIntro: boolean;
introFinished: boolean;
};
@ -53,7 +52,7 @@ const Starfield = memo((props: StarfieldProps) => {
}, []);
return (
<group visible={props.visible}>
<>
<group
position={[0, -1, 2]}
visible={props.shouldIntro ? mainVisible : true}
@ -126,7 +125,7 @@ const Starfield = memo((props: StarfieldProps) => {
) : (
<></>
)}
</group>
</>
);
});

View file

@ -156,13 +156,13 @@ const nodeManager = (eventState: any) => {
case "site_right":
case "select_level_up":
case "select_level_down":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return {
action: () => updateActiveNode(eventState.node, 3900),
};
case "change_node":
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return {
action: () => updateActiveNode(eventState.node),
};

View file

@ -5,7 +5,6 @@ const siteManager = (eventState: any) => {
const setRotX = useStore.getState().setSiteRotX;
const dispatchAction = (eventState: any) => {
console.log(eventState.siteRotY);
switch (eventState.event) {
case "site_left":
case "site_right":

View file

@ -7,6 +7,8 @@ const mediaManager = (eventState: any) => {
const setLeftComponentMatrixIdx = useStore.getState()
.setMediaLeftComponentMatrixIdx;
const setWordSelected = useStore.getState().setWordSelected;
const updateRightSide = useStore.getState().updateRightSide;
const resetScene = useStore.getState().resetMediaScene;
@ -71,7 +73,12 @@ const mediaManager = (eventState: any) => {
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
return { action: () => undefined };
return {
action: () => {
exitMedia();
setWordSelected(true);
},
};
}
};

View file

@ -21,7 +21,7 @@
],
"5": [
["20", "23", "16", "19"],
["12", "15", "09", "11"],
["12", "15", "08", "11"],
["04", "07", "00", "03"]
],
"6": [

View file

@ -1,30 +1,59 @@
import { OrbitControls } from "@react-three/drei";
import React, { Suspense, useEffect, useMemo } from "react";
import Preloader from "../components/Preloader";
import React, { Suspense, useEffect, useState } from "react";
import { useStore } from "../store";
import Pause from "../components/MainScene/PauseSubscene/Pause";
import SyncedComponentLoader from "../components/MainScene/SyncedComponentLoader";
import LevelSelection from "../components/MainScene/SyncedComponents/LevelSelection";
import HUD from "../components/MainScene/SyncedComponents/HUD";
import YellowTextRenderer from "../components/TextRenderer/YellowTextRenderer";
import YellowOrb from "../components/MainScene/SyncedComponents/YellowOrb";
import MiddleRing from "../components/MainScene/SyncedComponents/MiddleRing";
import GrayPlanes from "../components/MainScene/SyncedComponents/GrayPlanes";
import Starfield from "../components/MainScene/SyncedComponents/Starfield";
import Site from "../components/MainScene/SyncedComponents/Site";
import Lain from "../components/MainScene/Lain";
const MainScene = () => {
const currentSubscene = useStore((state) => state.mainSubscene);
const shouldIntro = useStore((state) => state.intro);
const [paused, setPaused] = useState(false);
const subscene = useStore((state) => state.mainSubscene);
const isPaused = useMemo(() => currentSubscene === "pause", [
currentSubscene,
]);
const wordSelected = useStore((state) => state.wordSelected);
const setWordSelected = useStore((state) => state.setWordSelected);
useEffect(() => {
return () => {
document.getElementsByTagName("canvas")[0].className = "";
};
}, []);
if (subscene === "pause") {
setTimeout(() => {
setPaused(true);
}, 3400);
} else {
setPaused(false);
}
}, [subscene]);
useEffect(() => {
if (wordSelected) {
setTimeout(() => {
setWordSelected(false);
}, 3100);
}
}, [setWordSelected, wordSelected]);
return (
<perspectiveCamera position-z={3}>
<Suspense fallback={null}>
<LevelSelection />
<Pause />
<SyncedComponentLoader paused={isPaused} shouldIntro={shouldIntro} />
<group visible={!paused}>
<group visible={!wordSelected}>
<HUD />
<YellowTextRenderer />
<MiddleRing />
<GrayPlanes />
<Lain shouldIntro={false} />
</group>
<YellowOrb visible={!paused} />
<Starfield shouldIntro={false} introFinished={true} />
</group>
<Site shouldIntro={false} introFinished={true} />
<OrbitControls />
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />
<pointLight color={0x7f7f7f} position={[0, 10, 0]} intensity={1.5} />

View file

@ -53,6 +53,7 @@ type State = {
rightSideIdx: 0 | 1 | 2;
};
mediaWordPosStateIdx: number;
wordSelected: boolean;
// idle scene
idleMedia: string;
@ -114,7 +115,7 @@ export const useStore = create(
combine(
{
// scene data
currentScene: "media",
currentScene: "main",
// game progress
gameProgress: game_progress,
@ -198,6 +199,7 @@ export const useStore = create(
rightSideIdx: 0,
},
mediaWordPosStateIdx: 1,
wordSelected: false,
// idle scene
idleMedia: "INS01.STR",
@ -350,6 +352,7 @@ export const useStore = create(
rightSideIdx: 0,
},
})),
setWordSelected: (to: boolean) => set(() => ({ wordSelected: to })),
// idle media setters
setIdleMedia: (to: any) => set(() => ({ idleMedia: to })),

View file

@ -46,7 +46,9 @@ export const findNodeFromWord = (
const matrixIndices = Object.entries(node_matrices).flatMap((matrixData) =>
matrixData[1].flatMap((row, idx) =>
row[0] === pos ? { matrixIdx: matrixData[0], rowIdx: idx, colIdx: 0 } : []
row[0] === pos
? { matrixIdx: parseInt(matrixData[0]), rowIdx: idx, colIdx: 0 }
: []
)
)[0];
@ -66,7 +68,8 @@ export const findNodeFromWord = (
...chosenNode,
matrixIndices: matrixIndices,
},
siteRotY: rotValues[matrixIndices.matrixIdx as keyof typeof rotValues],
siteRotY:
rotValues[matrixIndices.matrixIdx.toString() as keyof typeof rotValues],
level: chosenNode.id.substr(0, 2),
};
};