mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
explosion anim wip
This commit is contained in:
parent
49a31b127a
commit
af0df3e250
7 changed files with 136 additions and 30 deletions
|
@ -9,6 +9,7 @@ import Starfield from "./SyncedComponents/Starfield";
|
|||
import Site from "./SyncedComponents/Site";
|
||||
import MiddleRing from "./SyncedComponents/MiddleRing";
|
||||
import { a } from "@react-spring/three";
|
||||
import NodeExplosion from "./SyncedComponents/Site/NodeExplosion";
|
||||
|
||||
type SyncedComponentLoaderProps = {
|
||||
paused: boolean;
|
||||
|
|
|
@ -4,18 +4,25 @@ import { a, useSpring } from "@react-spring/three";
|
|||
import * as THREE from "three";
|
||||
import Cou from "../../../../static/sprite/Cou.png";
|
||||
import CouActive from "../../../../static/sprite/Cou_active.png";
|
||||
import CouGold from "../../../../static/sprite/Cou_gold.png";
|
||||
import Dc from "../../../../static/sprite/Dc.png";
|
||||
import DcActive from "../../../../static/sprite/Dc_active.png";
|
||||
import DcGold from "../../../../static/sprite/Dc_gold.png";
|
||||
import SSkn from "../../../../static/sprite/SSkn.png";
|
||||
import SSKnActive from "../../../../static/sprite/SSkn_active.png";
|
||||
import SSKnGold from "../../../../static/sprite/SSkn_gold.png";
|
||||
import Tda from "../../../../static/sprite/Tda.png";
|
||||
import TdaActive from "../../../../static/sprite/Tda_active.png";
|
||||
import TdaGold from "../../../../static/sprite/Tda_gold.png";
|
||||
import Dia from "../../../../static/sprite/Dia.png";
|
||||
import DiaActive from "../../../../static/sprite/Dia_active.png";
|
||||
import DiaGold from "../../../../static/sprite/Dia_gold.png";
|
||||
import Lda from "../../../../static/sprite/Lda.png";
|
||||
import LdaActive from "../../../../static/sprite/Lda_active.png";
|
||||
import LdaGold from "../../../../static/sprite/Lda_gold.png";
|
||||
import MULTI from "../../../../static/sprite/MULTI.png";
|
||||
import MULTIActive from "../../../../static/sprite/MULTI_active.png";
|
||||
import MULTIGold from "../../../../static/sprite/MULTI_gold.png";
|
||||
import level_y_values from "../../../../resources/level_y_values.json";
|
||||
import { useNodeStore } from "../../../../store";
|
||||
|
||||
|
@ -35,26 +42,26 @@ const Node = (props: NodeContructorProps) => {
|
|||
|
||||
const spriteToPath = (sprite: string) => {
|
||||
if (sprite.includes("S")) {
|
||||
return [SSkn, SSKnActive];
|
||||
return [SSkn, SSKnActive, SSKnGold];
|
||||
} else if (
|
||||
sprite.startsWith("P") ||
|
||||
sprite.startsWith("G") ||
|
||||
sprite.includes("?")
|
||||
) {
|
||||
return [MULTI, MULTIActive];
|
||||
return [MULTI, MULTIActive, MULTIGold];
|
||||
} else if (sprite.includes("Dc")) {
|
||||
return [Dc, DcActive];
|
||||
return [Dc, DcActive, DcGold];
|
||||
} else {
|
||||
const spriteAssocs = {
|
||||
Tda: [Tda, TdaActive],
|
||||
Cou: [Cou, CouActive],
|
||||
Dia: [Dia, DiaActive],
|
||||
Lda: [Lda, LdaActive],
|
||||
Ere: [MULTI, MULTIActive],
|
||||
Ekm: [MULTI, MULTIActive],
|
||||
Eda: [MULTI, MULTIActive],
|
||||
TaK: [MULTI, MULTIActive],
|
||||
Env: [MULTI, MULTIActive],
|
||||
Tda: [Tda, TdaActive, TdaGold],
|
||||
Cou: [Cou, CouActive, CouGold],
|
||||
Dia: [Dia, DiaActive, DiaGold],
|
||||
Lda: [Lda, LdaActive, LdaGold],
|
||||
Ere: [MULTI, MULTIActive, MULTIGold],
|
||||
Ekm: [MULTI, MULTIActive, MULTIGold],
|
||||
Eda: [MULTI, MULTIActive, MULTIGold],
|
||||
TaK: [MULTI, MULTIActive, MULTIGold],
|
||||
Env: [MULTI, MULTIActive, MULTIGold],
|
||||
};
|
||||
|
||||
return spriteAssocs[sprite.substr(0, 3) as keyof typeof spriteAssocs];
|
||||
|
@ -63,18 +70,21 @@ const Node = (props: NodeContructorProps) => {
|
|||
|
||||
const materialRef = useRef<THREE.ShaderMaterial>();
|
||||
|
||||
const spriteSheet = spriteToPath(props.sprite);
|
||||
const sprite = spriteToPath(props.sprite);
|
||||
|
||||
const nonActiveTexture = useLoader(THREE.TextureLoader, spriteSheet[0]);
|
||||
const activeTexture = useLoader(THREE.TextureLoader, spriteSheet[1]);
|
||||
const nonActiveTexture = useLoader(THREE.TextureLoader, sprite[0]);
|
||||
const activeTexture = useLoader(THREE.TextureLoader, sprite[1]);
|
||||
const goldTexture = useLoader(THREE.TextureLoader, sprite[2]);
|
||||
|
||||
const uniforms = useMemo(
|
||||
() => ({
|
||||
tex1: { type: "t", value: nonActiveTexture },
|
||||
tex2: { type: "t", value: activeTexture },
|
||||
tex3: { type: "t", value: goldTexture },
|
||||
goldTextureBias: { value: 0 },
|
||||
timeMSeconds: { value: (Date.now() % (Math.PI * 2000)) / 1000.0 },
|
||||
}),
|
||||
[nonActiveTexture, activeTexture]
|
||||
[nonActiveTexture, activeTexture, goldTexture]
|
||||
);
|
||||
|
||||
const vertexShader = `
|
||||
|
@ -91,7 +101,9 @@ const Node = (props: NodeContructorProps) => {
|
|||
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
uniform sampler2D tex3;
|
||||
uniform float timeMSeconds;
|
||||
uniform float goldTextureBias;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
|
@ -100,22 +112,24 @@ const Node = (props: NodeContructorProps) => {
|
|||
void main() {
|
||||
vec4 t1 = texture2D(tex1,vUv);
|
||||
vec4 t2 = texture2D(tex2,vUv);
|
||||
vec4 t3 = texture2D(tex3,vUv);
|
||||
float bias = abs(sin(timeMSeconds / (1.6 / M_PI)));
|
||||
gl_FragColor = mix(t1, t2, bias);
|
||||
gl_FragColor = mix(mix(t1, t2, bias), t3, goldTextureBias);
|
||||
}
|
||||
`;
|
||||
|
||||
useFrame(() => {
|
||||
if (materialRef.current) {
|
||||
materialRef.current.uniforms.timeMSeconds.value =
|
||||
(Date.now() % (Math.PI * 2000)) / 1000.0;
|
||||
}
|
||||
});
|
||||
|
||||
// these pieces of state get updated transiently rather than reactively
|
||||
// to avoid excess unnecessary renders (this is absolutely crucial for performance).
|
||||
|
||||
const [
|
||||
{ activeNodePosX, activeNodePosY, activeNodePosZ, activeNodeRotZ, activeNodeRotY },
|
||||
{
|
||||
activeNodePosX,
|
||||
activeNodePosY,
|
||||
activeNodePosZ,
|
||||
activeNodeRotZ,
|
||||
activeNodeRotY,
|
||||
goldTextureBias,
|
||||
},
|
||||
set,
|
||||
] = useSpring(() => ({
|
||||
activeNodePosX: useNodeStore.getState().activeNodeState.interactedWith
|
||||
|
@ -134,6 +148,7 @@ const Node = (props: NodeContructorProps) => {
|
|||
activeNodeRotY: useNodeStore.getState().activeNodeState.interactedWith
|
||||
? useNodeStore.getState().activeNodeState.rotY
|
||||
: props.rotation[1],
|
||||
goldTextureBias: useNodeStore.getState().activeNodeState.goldTextureBias,
|
||||
config: { duration: 800 },
|
||||
}));
|
||||
|
||||
|
@ -154,6 +169,7 @@ const Node = (props: NodeContructorProps) => {
|
|||
activeNodeRotY: useNodeStore.getState().activeNodeState.interactedWith
|
||||
? state.activeNodeState.rotY
|
||||
: props.rotation[1],
|
||||
goldTextureBias: useNodeStore.getState().activeNodeState.goldTextureBias,
|
||||
}));
|
||||
}, [
|
||||
props.level,
|
||||
|
@ -165,6 +181,14 @@ const Node = (props: NodeContructorProps) => {
|
|||
props.rotation,
|
||||
]);
|
||||
|
||||
useFrame(() => {
|
||||
if (materialRef.current) {
|
||||
materialRef.current.uniforms.timeMSeconds.value =
|
||||
(Date.now() % (Math.PI * 2000)) / 1000.0;
|
||||
materialRef.current.uniforms.goldTextureBias.value = goldTextureBias.get();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group
|
||||
position={[
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import React, { useMemo } from "react";
|
||||
import { a } from "@react-spring/three";
|
||||
import * as THREE from "three";
|
||||
import ExplosionLine from "./NodeExplosion/ExplosionLine";
|
||||
|
||||
const NodeExplosion = () => {
|
||||
return <ExplosionLine rotation={[0, 0, -0.3]} color={"#f5cc16"} length={1} />;
|
||||
};
|
||||
|
||||
export default NodeExplosion;
|
|
@ -0,0 +1,67 @@
|
|||
import React, { useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
import { a } from "@react-spring/three";
|
||||
|
||||
type LineProps = {
|
||||
rotation: number[];
|
||||
color: string;
|
||||
length: number;
|
||||
};
|
||||
|
||||
const ExplosionLine = (props: LineProps) => {
|
||||
const uniforms = useMemo(
|
||||
() => ({
|
||||
color1: {
|
||||
value: new THREE.Color("white"),
|
||||
},
|
||||
color2: {
|
||||
value: new THREE.Color(props.color),
|
||||
},
|
||||
}),
|
||||
[props.color]
|
||||
);
|
||||
|
||||
const vertexShader = `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const fragmentShader = `
|
||||
uniform vec3 color1;
|
||||
uniform vec3 color2;
|
||||
uniform float alpha;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
float alpha = smoothstep(0.0, 1.0, vUv.y);
|
||||
float colorMix = smoothstep(1.0, 2.0, 1.8);
|
||||
|
||||
gl_FragColor = vec4(mix(color1, color2, colorMix), alpha) * 0.8;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<mesh
|
||||
rotation={props.rotation as [number, number, number]}
|
||||
scale={[0.01, props.length, 0]}
|
||||
renderOrder={-1}
|
||||
>
|
||||
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
|
||||
<a.shaderMaterial
|
||||
attach="material"
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
uniforms={uniforms}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExplosionLine;
|
|
@ -103,12 +103,16 @@ const NodeManager = (props: StateManagerProps) => {
|
|||
setTimeout(() => {
|
||||
setActiveNodeState(Math.PI, "rotZ");
|
||||
setActiveNodeState(Math.PI, "rotY");
|
||||
setActiveNodeState(Math.PI, "rotX");
|
||||
setActiveNodeState(1, "goldTextureBias");
|
||||
}, 1200);
|
||||
|
||||
setTimeout(() => {
|
||||
setActiveNodeState(false, "interactedWith");
|
||||
setActiveNodeState(0, "rotZ");
|
||||
setActiveNodeState(0, "rotY");
|
||||
setActiveNodeState(0, "rotX");
|
||||
setActiveNodeState(0, "goldTextureBias");
|
||||
}, 2500);
|
||||
},
|
||||
[setActiveNodeState]
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useMainSceneStore } from "../store";
|
|||
import Pause from "../components/MainScene/PauseSubscene/Pause";
|
||||
import SyncedComponentLoader from "../components/MainScene/SyncedComponentLoader";
|
||||
import LevelSelection from "../components/MainScene/SyncedComponents/LevelSelection";
|
||||
import NodeExplosion from "../components/MainScene/SyncedComponents/Site/NodeExplosion";
|
||||
|
||||
const MainScene = () => {
|
||||
const currentSubscene = useMainSceneStore((state) => state.subscene);
|
||||
|
@ -36,8 +37,9 @@ const MainScene = () => {
|
|||
<pointLight color={0x7f7f7f} position={[0, 10, 0]} intensity={1.5} />
|
||||
<pointLight color={0xffffff} position={[8, 0, 0]} intensity={0.2} />
|
||||
<pointLight color={0xffffff} position={[-8, 0, 0]} intensity={0.2} />
|
||||
<NodeExplosion />
|
||||
</a.group>
|
||||
<Lain shouldIntro={shouldIntro} />
|
||||
{/*<Lain shouldIntro={shouldIntro} />*/}
|
||||
</Suspense>
|
||||
</perspectiveCamera>
|
||||
);
|
||||
|
|
|
@ -65,6 +65,7 @@ type NodeState = {
|
|||
rotY: number;
|
||||
rotZ: number;
|
||||
interactedWith: boolean;
|
||||
goldTextureBias: number;
|
||||
};
|
||||
nodeMatrixIndices: { matrixIdx: number; rowIdx: number; colIdx: number };
|
||||
gameProgress: typeof game_progress;
|
||||
|
@ -289,10 +290,6 @@ export const useHudStore = create<HUDState>((set) => ({
|
|||
export const useNodeStore = create(
|
||||
combine(
|
||||
{
|
||||
siteASave: {
|
||||
activeNodeId: "0422",
|
||||
nodeMatrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
|
||||
},
|
||||
activeNodeState: {
|
||||
id: "0422",
|
||||
posX: 0,
|
||||
|
@ -301,6 +298,7 @@ export const useNodeStore = create(
|
|||
rotY: 0,
|
||||
posY: 0,
|
||||
interactedWith: false,
|
||||
goldTextureBias: 0,
|
||||
},
|
||||
nodeMatrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
|
||||
gameProgress: game_progress,
|
||||
|
|
Loading…
Reference in a new issue