mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
all node interaction animations finished
This commit is contained in:
parent
62e5be1d52
commit
7b67f44135
11 changed files with 247 additions and 48 deletions
|
@ -192,7 +192,7 @@ const Lain = (props: LainProps) => {
|
|||
select_level_up: <LainMoveUp />,
|
||||
throw_node: <LainThrowNode />,
|
||||
pause_game: <LainRipMiddleRing />,
|
||||
test: <LainRipNode />,
|
||||
rip_node: <LainRipNode />,
|
||||
};
|
||||
|
||||
const [introFinished, setIntroFinished] = useState(false);
|
||||
|
|
|
@ -122,6 +122,7 @@ const Node = (props: NodeContructorProps) => {
|
|||
activeNodePosZ,
|
||||
activeNodeRotZ,
|
||||
activeNodeVisible,
|
||||
activeNodeScale,
|
||||
},
|
||||
set,
|
||||
] = useSpring(() => ({
|
||||
|
@ -138,6 +139,9 @@ const Node = (props: NodeContructorProps) => {
|
|||
activeNodeRotZ: useNodeStore.getState().activeNodeState.interactedWith
|
||||
? useNodeStore.getState().activeNodeState.rotZ
|
||||
: 0,
|
||||
activeNodeScale: useNodeStore.getState().activeNodeState.shrinking
|
||||
? 0
|
||||
: 1,
|
||||
activeNodeVisible: true,
|
||||
config: { duration: 800 },
|
||||
}));
|
||||
|
@ -156,6 +160,9 @@ const Node = (props: NodeContructorProps) => {
|
|||
activeNodeRotZ: useNodeStore.getState().activeNodeState.interactedWith
|
||||
? state.activeNodeState.rotZ
|
||||
: 0,
|
||||
activeNodeScale: useNodeStore.getState().activeNodeState.shrinking
|
||||
? 0
|
||||
: 1,
|
||||
activeNodeVisible: useNodeStore.getState().activeNodeState.visible,
|
||||
}));
|
||||
}, [
|
||||
|
@ -184,27 +191,33 @@ const Node = (props: NodeContructorProps) => {
|
|||
]}
|
||||
>
|
||||
{props.active ? (
|
||||
<a.mesh
|
||||
position-x={activeNodePosX}
|
||||
position-y={activeNodePosY}
|
||||
position-z={activeNodePosZ}
|
||||
rotation-z={activeNodeRotZ}
|
||||
rotation-y={props.rotation[1]}
|
||||
visible={activeNodeVisible}
|
||||
scale={[0.36, 0.18, 0.36]}
|
||||
renderOrder={1}
|
||||
<a.group
|
||||
scale-x={activeNodeScale}
|
||||
scale-y={activeNodeScale}
|
||||
scale-z={activeNodeScale}
|
||||
>
|
||||
<planeBufferGeometry attach="geometry" />
|
||||
<shaderMaterial
|
||||
ref={materialRef}
|
||||
attach="material"
|
||||
uniforms={uniforms}
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
side={THREE.DoubleSide}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.mesh>
|
||||
<a.mesh
|
||||
position-x={activeNodePosX}
|
||||
position-y={activeNodePosY}
|
||||
position-z={activeNodePosZ}
|
||||
rotation-z={activeNodeRotZ}
|
||||
rotation-y={props.rotation[1]}
|
||||
visible={activeNodeVisible}
|
||||
scale={[0.36, 0.18, 0.36]}
|
||||
renderOrder={1}
|
||||
>
|
||||
<planeBufferGeometry attach="geometry" />
|
||||
<shaderMaterial
|
||||
ref={materialRef}
|
||||
attach="material"
|
||||
uniforms={uniforms}
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
side={THREE.DoubleSide}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.mesh>
|
||||
</a.group>
|
||||
) : (
|
||||
<a.mesh
|
||||
position-x={props.position[0]}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React, { useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
import { a } from "@react-spring/three";
|
||||
|
||||
type LineProps = {
|
||||
rotation: number[];
|
||||
|
@ -56,7 +55,7 @@ const ExplosionLine = (props: LineProps) => {
|
|||
renderOrder={2}
|
||||
>
|
||||
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
|
||||
<a.shaderMaterial
|
||||
<shaderMaterial
|
||||
attach="material"
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
|
|
|
@ -1,26 +1,112 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import TriangleNode from "./NodeRip/TriangleNode";
|
||||
import { useNodeStore } from "../../../../../store";
|
||||
import ExplosionLine from "./NodeExplosion/ExplosionLine";
|
||||
import RipLine from "./NodeRip/RipLine";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
|
||||
const NodeRip = () => {
|
||||
const nodeShrinking = useNodeStore(
|
||||
(state) => state.activeNodeState.shrinking
|
||||
);
|
||||
const [shouldAnimate, setShouldAnimate] = useState(false);
|
||||
|
||||
const LCG = (a: number, c: number, m: number, s: number) => () =>
|
||||
(s = (s * a + c) % m);
|
||||
|
||||
const lcgInstance = LCG(1664525, 1013904223, 2 ** 32, 2);
|
||||
|
||||
const firstLineSet = Array.from({ length: 25 }, (_, idx) => {
|
||||
let coordSet = [lcgInstance() / 7000000000, lcgInstance() / 7000000000];
|
||||
if (coordSet[0] > 0.45) coordSet[0] = coordSet[0] * -1;
|
||||
if (coordSet[1] > 0.45) coordSet[1] = coordSet[1] * -1;
|
||||
|
||||
const color = idx % 2 === 0 ? "red" : "yellow";
|
||||
|
||||
return { coordinates: coordSet, color: color };
|
||||
});
|
||||
|
||||
const sndLineSet = Array.from({ length: 25 }, (_, idx) => {
|
||||
let coordSet = [lcgInstance() / 6000000000, lcgInstance() / 6000000000];
|
||||
if (coordSet[0] > 0.65) coordSet[0] = coordSet[0] * -1;
|
||||
if (coordSet[1] > 0.65) coordSet[1] = coordSet[1] * -1;
|
||||
|
||||
const color = idx % 2 === 0 ? "yellow" : "red";
|
||||
|
||||
return { coordinates: coordSet, color: color };
|
||||
});
|
||||
|
||||
const [currentFrame, setCurrentFrame] = useState(0);
|
||||
|
||||
const lastTime = useRef(0);
|
||||
|
||||
useFrame(() => {
|
||||
if (shouldAnimate) {
|
||||
const now = Date.now();
|
||||
if (currentFrame < 3) {
|
||||
if (now > lastTime.current + 200) {
|
||||
setCurrentFrame(currentFrame + 1);
|
||||
lastTime.current = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeShrinking) {
|
||||
setTimeout(() => {
|
||||
setShouldAnimate(true);
|
||||
}, 1150);
|
||||
} else {
|
||||
setShouldAnimate(false);
|
||||
setCurrentFrame(1);
|
||||
}
|
||||
}, [nodeShrinking]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<group visible={shouldAnimate}>
|
||||
<TriangleNode
|
||||
rotation={[1.3, 1.6, 0]}
|
||||
pivotRotation={[0, -Math.PI / 4 - 0.5, 0]}
|
||||
shouldAnimate={shouldAnimate}
|
||||
/>
|
||||
<TriangleNode
|
||||
rotation={[0.4, 0.3, 0]}
|
||||
pivotRotation={[0, -Math.PI / 8, 0]}
|
||||
shouldAnimate={shouldAnimate}
|
||||
/>
|
||||
<TriangleNode
|
||||
rotation={[1.6, 2.6, 0]}
|
||||
pivotRotation={[0, Math.PI / 4 + 0.5, 0]}
|
||||
shouldAnimate={shouldAnimate}
|
||||
/>
|
||||
<TriangleNode
|
||||
rotation={[-0.7, 1.8, 0]}
|
||||
pivotRotation={[0, Math.PI / 8, 0]}
|
||||
shouldAnimate={shouldAnimate}
|
||||
/>
|
||||
</>
|
||||
<group position={[-0.05, -0.3, 0.1]}>
|
||||
<group visible={currentFrame === 1}>
|
||||
{firstLineSet.map((data, idx) => (
|
||||
<RipLine
|
||||
color={data.color}
|
||||
endPoints={data.coordinates}
|
||||
key={idx}
|
||||
/>
|
||||
))}
|
||||
</group>
|
||||
|
||||
<group visible={currentFrame === 2}>
|
||||
{sndLineSet.map((data, idx) => (
|
||||
<RipLine
|
||||
color={data.color}
|
||||
endPoints={data.coordinates}
|
||||
key={idx}
|
||||
/>
|
||||
))}
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import React, { useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
|
||||
type RipLineProps = {
|
||||
color: string;
|
||||
endPoints: number[];
|
||||
};
|
||||
|
||||
const RipLine = (props: RipLineProps) => {
|
||||
const horizontalPoints = useMemo(
|
||||
() => [
|
||||
new THREE.Vector3(0, 0, 0),
|
||||
new THREE.Vector3(props.endPoints[0], props.endPoints[1], 0),
|
||||
],
|
||||
[props.endPoints]
|
||||
);
|
||||
|
||||
return (
|
||||
<line>
|
||||
<geometry attach="geometry" vertices={horizontalPoints} />
|
||||
<lineBasicMaterial
|
||||
attach="material"
|
||||
color={props.color === "yellow" ? "#f5cc16" : "#e33d00"}
|
||||
transparent={true}
|
||||
opacity={0.4}
|
||||
/>
|
||||
</line>
|
||||
);
|
||||
};
|
||||
|
||||
export default RipLine;
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useRef } from "react";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import MULTI from "../../../../../../static/sprite/MULTI.png";
|
||||
import { useFrame, useLoader } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
|
@ -6,6 +6,7 @@ import * as THREE from "three";
|
|||
type TriangleNodeProps = {
|
||||
rotation: number[];
|
||||
pivotRotation: number[];
|
||||
shouldAnimate: boolean;
|
||||
};
|
||||
|
||||
const TriangleNode = (props: TriangleNodeProps) => {
|
||||
|
@ -14,15 +15,21 @@ const TriangleNode = (props: TriangleNodeProps) => {
|
|||
const triangleNodeRef = useRef<THREE.Object3D>();
|
||||
|
||||
useFrame(() => {
|
||||
if (triangleNodeRef.current) {
|
||||
triangleNodeRef.current.position.z += 0.01;
|
||||
if (triangleNodeRef.current && props.shouldAnimate) {
|
||||
triangleNodeRef.current.position.z += 0.05;
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (triangleNodeRef.current && !props.shouldAnimate) {
|
||||
triangleNodeRef.current.position.z = 0;
|
||||
}
|
||||
}, [props.shouldAnimate]);
|
||||
|
||||
return (
|
||||
<group rotation={props.pivotRotation as [number, number, number]}>
|
||||
<mesh
|
||||
position={[-0.1, -0.2, 0.1]}
|
||||
position={[-0.1, -0.3, 0.1]}
|
||||
rotation={props.rotation as [number, number, number]}
|
||||
scale={[0.1, 0.1, 0.1]}
|
||||
ref={triangleNodeRef}
|
||||
|
|
|
@ -15,6 +15,7 @@ const LainManager = (props: StateManagerProps) => {
|
|||
case "select_level_up":
|
||||
case "select_level_down":
|
||||
case "pause_game":
|
||||
case "knock_node":
|
||||
return {
|
||||
action: setLainMoveState,
|
||||
value: eventState.event,
|
||||
|
@ -29,11 +30,14 @@ const LainManager = (props: StateManagerProps) => {
|
|||
value: "throw_node",
|
||||
duration: 3900,
|
||||
};
|
||||
case "knock_node":
|
||||
case "rip_node_media":
|
||||
case "rip_node_gate":
|
||||
case "rip_node_sskn":
|
||||
case "rip_node_tak":
|
||||
return {
|
||||
action: setLainMoveState,
|
||||
value: "knock_node",
|
||||
duration: 3900,
|
||||
value: "rip_node",
|
||||
duration: 6000,
|
||||
};
|
||||
case "knock_node_and_fall":
|
||||
return {
|
||||
|
@ -41,12 +45,6 @@ const LainManager = (props: StateManagerProps) => {
|
|||
value: "knock_node_and_fall",
|
||||
duration: 6000,
|
||||
};
|
||||
case "test":
|
||||
return {
|
||||
action: setLainMoveState,
|
||||
value: "test",
|
||||
duration: 3900,
|
||||
};
|
||||
}
|
||||
},
|
||||
[setLainMoveState]
|
||||
|
|
|
@ -122,6 +122,55 @@ const NodeManager = (props: StateManagerProps) => {
|
|||
[setActiveNodeState]
|
||||
);
|
||||
|
||||
const animateShrinkAndRip = useCallback(
|
||||
(siteRotY: number) => {
|
||||
setActiveNodeState(true, "interactedWith");
|
||||
|
||||
const fstCoordSet = calculateCoordsBasedOnRotation(0.9, 0.3, siteRotY);
|
||||
const sndCoordSet = calculateCoordsBasedOnRotation(0.5, 0.2, siteRotY);
|
||||
const thirdCoordSet = calculateCoordsBasedOnRotation(0, 0.2, siteRotY);
|
||||
|
||||
setActiveNodeState(fstCoordSet.x, "posX");
|
||||
setActiveNodeState(fstCoordSet.z, "posZ");
|
||||
setActiveNodeState(0, "posY");
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(sndCoordSet.x, "posX");
|
||||
setActiveNodeState(sndCoordSet.z, "posZ");
|
||||
}, 800);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(thirdCoordSet.x, "posX");
|
||||
setActiveNodeState(thirdCoordSet.z, "posZ");
|
||||
setActiveNodeState(-0.4, "posY");
|
||||
}, 2800);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(true, "shrinking");
|
||||
}, 3000);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(-1.5, "posY");
|
||||
}, 3200);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(false, "visible");
|
||||
}, 3500);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(false, "interactedWith");
|
||||
setActiveNodeState(false, "shrinking");
|
||||
setActiveNodeState(0, "rotZ");
|
||||
setActiveNodeState(0, "rotX");
|
||||
}, 6400);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(true, "visible");
|
||||
}, 7500);
|
||||
},
|
||||
[setActiveNodeState]
|
||||
);
|
||||
|
||||
const updateActiveNode = useCallback(
|
||||
(
|
||||
newActiveNodeId: string,
|
||||
|
@ -181,14 +230,17 @@ const NodeManager = (props: StateManagerProps) => {
|
|||
action: animateActiveNodeThrow,
|
||||
value: [eventState.siteRotY],
|
||||
};
|
||||
case "test":
|
||||
case "rip_node_media":
|
||||
case "rip_node_gate":
|
||||
case "rip_node_sskn":
|
||||
case "rip_node_tak":
|
||||
return {
|
||||
action: animateNodeTouchAndScare,
|
||||
action: animateShrinkAndRip,
|
||||
value: [eventState.siteRotY],
|
||||
};
|
||||
}
|
||||
},
|
||||
[animateActiveNodeThrow, animateNodeKnock, updateActiveNode]
|
||||
[animateActiveNodeThrow, animateShrinkAndRip, updateActiveNode]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -19,6 +19,17 @@ const SceneManager = (props: StateManagerProps) => {
|
|||
delay: 3450,
|
||||
setMainSceneIntro: false,
|
||||
};
|
||||
case "rip_node_media":
|
||||
case "rip_node_gate":
|
||||
case "rip_node_sskn":
|
||||
case "rip_node_tak":
|
||||
return {
|
||||
action: setScene,
|
||||
value: eventState.scene,
|
||||
delay: 6000,
|
||||
setMainSceneIntro: false,
|
||||
};
|
||||
|
||||
case "media_exit_select":
|
||||
case "exit_gate":
|
||||
case "sskn_cancel_select":
|
||||
|
|
|
@ -67,7 +67,7 @@ const handleMainSceneEvent = (gameContext: any) => {
|
|||
];
|
||||
const nodeType = nodeData.type;
|
||||
|
||||
const eventAnimation = "throw_node_";
|
||||
const eventAnimation = Math.random() < 0.4 ? "rip_node" : "throw_node";
|
||||
|
||||
switch (nodeType) {
|
||||
case 0:
|
||||
|
@ -75,24 +75,24 @@ const handleMainSceneEvent = (gameContext: any) => {
|
|||
case 4:
|
||||
case 3:
|
||||
case 5:
|
||||
event = eventAnimation + "media";
|
||||
event = `${eventAnimation}_media`;
|
||||
scene = "media";
|
||||
break;
|
||||
case 6:
|
||||
if (nodeData.node_name.substr(0, 3) === "TaK") {
|
||||
event = eventAnimation + "tak";
|
||||
event = `${eventAnimation}_tak`;
|
||||
scene = "tak";
|
||||
} else {
|
||||
event = eventAnimation + "media";
|
||||
event = `${eventAnimation}_media`;
|
||||
scene = "media";
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
event = eventAnimation + "gate";
|
||||
event = `${eventAnimation}_gate`;
|
||||
scene = "gate";
|
||||
break;
|
||||
case 7:
|
||||
event = eventAnimation + "sskn";
|
||||
event = `${eventAnimation}_sskn`;
|
||||
scene = "sskn";
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ type NodeState = {
|
|||
rotZ: number;
|
||||
interactedWith: boolean;
|
||||
exploding: boolean;
|
||||
shrinking: boolean;
|
||||
visible: boolean;
|
||||
};
|
||||
nodeMatrixIndices: { matrixIdx: number; rowIdx: number; colIdx: number };
|
||||
|
@ -298,6 +299,7 @@ export const useNodeStore = create(
|
|||
posY: 0,
|
||||
interactedWith: false,
|
||||
exploding: false,
|
||||
shrinking: false,
|
||||
visible: true,
|
||||
},
|
||||
nodeMatrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
|
||||
|
|
Loading…
Reference in a new issue