all node interaction animations finished

This commit is contained in:
ad044 2021-01-09 21:30:42 +04:00
parent 62e5be1d52
commit 7b67f44135
11 changed files with 247 additions and 48 deletions

View file

@ -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);

View file

@ -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]}

View file

@ -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}

View file

@ -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>
);
};

View file

@ -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;

View file

@ -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}

View file

@ -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]

View file

@ -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(() => {

View file

@ -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":

View file

@ -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;
}

View file

@ -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 },