mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
rewrote starfield
This commit is contained in:
parent
f27ab6d4f8
commit
abed73e236
8 changed files with 184 additions and 384 deletions
|
@ -9,7 +9,7 @@ import moveRightSpriteSheet from "../../static/sprite/move_right.png";
|
|||
import standingSpriteSheet from "../../static/sprite/standing.png";
|
||||
import introSpriteSheet from "../../static/sprite/intro.png";
|
||||
import throwNodeSpriteSheet from "../../static/sprite/throw_node.png";
|
||||
import { useLainStore } from "../../store";
|
||||
import { useLainStore, useMainSceneStore } from "../../store";
|
||||
|
||||
type LainConstructorProps = {
|
||||
sprite: string;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import * as THREE from "three";
|
||||
import PauseSquare from "./PauseSquare";
|
||||
import StaticBigLetter from "../TextRenderer/StaticBigLetter";
|
||||
import { usePauseStore } from "../../store";
|
||||
import StaticBigLetter from "../../TextRenderer/StaticBigLetter";
|
||||
import { usePauseStore } from "../../../store";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
|
||||
const Pause = (props: { visible: boolean }) => {
|
||||
const exit = usePauseStore((state) => state.exitAnimation);
|
||||
const [showActiveComponent, setShowActiveComponent] = useState(false);
|
||||
const [animation, setAnimation] = useState(false);
|
||||
const [intro, setIntro] = useState(true);
|
||||
|
@ -77,7 +78,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
[0, 1, 2, 3, 4, 5, 6].map((col: number) => {
|
||||
if (rowIdx === 5 && col > 0 && col < 5) {
|
||||
return col === 1 ? (
|
||||
<>
|
||||
<React.Fragment key={`Lfragment`}>
|
||||
<StaticBigLetter
|
||||
color={"white"}
|
||||
letter={"L"}
|
||||
|
@ -85,7 +86,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
position={[0.35, 1.8, 0]}
|
||||
scale={[0.25, 0.25, 0.25]}
|
||||
active={!(activeComponent === "load")}
|
||||
key={col}
|
||||
key={"whiteL"}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
intro={intro}
|
||||
|
@ -94,24 +95,24 @@ const Pause = (props: { visible: boolean }) => {
|
|||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
key={col}
|
||||
key={"whiteLsquare"}
|
||||
shouldDisappear={true}
|
||||
intro={intro}
|
||||
/>
|
||||
</>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<PauseSquare
|
||||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
active={!(activeComponent === "load")}
|
||||
key={col}
|
||||
key={`${rowIdx}${col}L`}
|
||||
intro={intro}
|
||||
/>
|
||||
);
|
||||
} else if (rowIdx === 4 && col > 4 && col < 7) {
|
||||
return col === 5 ? (
|
||||
<>
|
||||
<React.Fragment key={"AFragment"}>
|
||||
<StaticBigLetter
|
||||
color={"white"}
|
||||
letter={"A"}
|
||||
|
@ -119,7 +120,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
position={[1.78, 1.43, 0]}
|
||||
scale={[0.25, 0.25, 0]}
|
||||
active={!(activeComponent === "about")}
|
||||
key={col}
|
||||
key={"whiteA"}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
intro={intro}
|
||||
|
@ -128,24 +129,24 @@ const Pause = (props: { visible: boolean }) => {
|
|||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
key={col}
|
||||
key={"whiteAsquare"}
|
||||
shouldDisappear={true}
|
||||
intro={intro}
|
||||
/>
|
||||
</>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<PauseSquare
|
||||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
active={!(activeComponent === "about")}
|
||||
key={col}
|
||||
key={`${rowIdx}${col}A`}
|
||||
intro={intro}
|
||||
/>
|
||||
);
|
||||
} else if (rowIdx === 3 && col > 2 && col < 7) {
|
||||
return col === 3 ? (
|
||||
<>
|
||||
<React.Fragment key={"CFragment"}>
|
||||
<StaticBigLetter
|
||||
color={"white"}
|
||||
letter={"C"}
|
||||
|
@ -153,7 +154,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
position={[1.05, 1.07, 0]}
|
||||
scale={[0.25, 0.25, 0]}
|
||||
active={!(activeComponent === "change")}
|
||||
key={col}
|
||||
key={"whiteC"}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
intro={intro}
|
||||
|
@ -162,24 +163,24 @@ const Pause = (props: { visible: boolean }) => {
|
|||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
key={col}
|
||||
key={"whiteCsquare"}
|
||||
shouldDisappear={true}
|
||||
intro={intro}
|
||||
/>
|
||||
</>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<PauseSquare
|
||||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
active={!(activeComponent === "change")}
|
||||
key={col}
|
||||
key={`${rowIdx}${col}C`}
|
||||
intro={intro}
|
||||
/>
|
||||
);
|
||||
} else if (rowIdx === 1 && col > 0 && col < 5) {
|
||||
return col === 1 ? (
|
||||
<>
|
||||
<React.Fragment key={"Sfragment"}>
|
||||
<StaticBigLetter
|
||||
color={"white"}
|
||||
letter={"S"}
|
||||
|
@ -187,7 +188,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
position={[0.35, 0.35, 0]}
|
||||
scale={[0.25, 0.25, 0]}
|
||||
active={!(activeComponent === "save")}
|
||||
key={col}
|
||||
key={"whiteS"}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
intro={intro}
|
||||
|
@ -196,24 +197,24 @@ const Pause = (props: { visible: boolean }) => {
|
|||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
key={col}
|
||||
key={"whiteSsquare"}
|
||||
shouldDisappear={true}
|
||||
intro={intro}
|
||||
/>
|
||||
</>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<PauseSquare
|
||||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
active={!(activeComponent === "save")}
|
||||
key={col}
|
||||
key={`${rowIdx}${col}S`}
|
||||
intro={intro}
|
||||
/>
|
||||
);
|
||||
} else if (rowIdx === 0 && col > 4 && col < 7) {
|
||||
return col === 5 ? (
|
||||
<>
|
||||
<React.Fragment key={"Efragment"}>
|
||||
<StaticBigLetter
|
||||
color={"white"}
|
||||
letter={"E"}
|
||||
|
@ -221,7 +222,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
position={[1.78, 0, 0]}
|
||||
scale={[0.25, 0.25, 0]}
|
||||
active={!(activeComponent === "exit")}
|
||||
key={col}
|
||||
key={"whiteE"}
|
||||
rowIdx={1}
|
||||
colIdx={col}
|
||||
intro={intro}
|
||||
|
@ -230,18 +231,18 @@ const Pause = (props: { visible: boolean }) => {
|
|||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
key={col}
|
||||
key={"whiteEsquare"}
|
||||
shouldDisappear={true}
|
||||
intro={intro}
|
||||
/>
|
||||
</>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<PauseSquare
|
||||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
active={!(activeComponent === "exit")}
|
||||
key={col}
|
||||
key={`${rowIdx}${col}E`}
|
||||
intro={intro}
|
||||
/>
|
||||
);
|
||||
|
@ -251,7 +252,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
geometry={squareGeoms[row][col]}
|
||||
rowIdx={rowIdx}
|
||||
colIdx={col}
|
||||
key={col}
|
||||
key={`${rowIdx}${col}r`}
|
||||
active={true}
|
||||
intro={intro}
|
||||
/>
|
||||
|
@ -319,7 +320,7 @@ const Pause = (props: { visible: boolean }) => {
|
|||
/>
|
||||
))}
|
||||
|
||||
<group visible={showActiveComponent}>
|
||||
<group visible={!exit}>
|
||||
<sprite position={[0.5, -0.8, 0]} scale={[3, 1, 0]} renderOrder={100}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
import pauseGrayBoxes from "../../static/sprite/pause_gray_boxes.png";
|
||||
import pauseGrayBoxes from "../../../static/sprite/pause_gray_boxes.png";
|
||||
import { a, useSpring } from "@react-spring/three";
|
||||
import { usePauseStore } from "../../store";
|
||||
import { usePauseStore } from "../../../store";
|
||||
|
||||
type PauseSquareProps = {
|
||||
colIdx: number;
|
|
@ -1,346 +0,0 @@
|
|||
import { a, useSpring } from "@react-spring/three";
|
||||
import React, { createRef, memo, RefObject, useMemo, useRef } from "react";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import { useStarfieldStore } from "../../store";
|
||||
|
||||
type StarRefsAndInitialPoses = [
|
||||
React.MutableRefObject<React.RefObject<THREE.Object3D>[]>,
|
||||
number[][]
|
||||
][];
|
||||
|
||||
type StarfieldObjectData = {
|
||||
starPoses: number[][];
|
||||
ref: React.MutableRefObject<React.RefObject<THREE.Object3D>[]>;
|
||||
rotation: number[];
|
||||
positionSpecifier: number[];
|
||||
uniform?:
|
||||
| { color1: { value: THREE.Color }; color2: { value: THREE.Color } }
|
||||
| undefined;
|
||||
};
|
||||
|
||||
type IntroStarfieldObjectData = {
|
||||
starPoses: number[][];
|
||||
ref: React.MutableRefObject<React.RefObject<THREE.Object3D>[]>;
|
||||
uniform?:
|
||||
| { color1: { value: THREE.Color }; color2: { value: THREE.Color } }
|
||||
| undefined;
|
||||
};
|
||||
|
||||
const Starfield = memo(() => {
|
||||
const introStarfieldGroupRef = useRef<THREE.Object3D>();
|
||||
|
||||
const introStarfieldVisible = useStarfieldStore(
|
||||
(state) => state.introStarfieldVisible
|
||||
);
|
||||
const mainStarfieldVisible = useStarfieldStore(
|
||||
(state) => state.mainStarfieldVisible
|
||||
);
|
||||
|
||||
const mainStarfieldBoostVal = useStarfieldStore(
|
||||
(state) => state.mainStarfieldBoostVal
|
||||
);
|
||||
|
||||
const starfieldState = useSpring({
|
||||
starfieldBoostVal: mainStarfieldBoostVal,
|
||||
config: { duration: 1200 },
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
`;
|
||||
|
||||
const LCG = (a: number, c: number, m: number, s: number) => () =>
|
||||
(s = (s * a + c) % m);
|
||||
|
||||
const lcgInstance = LCG(1664525, 1013904223, 2 ** 32, 2);
|
||||
|
||||
const uniformConstructor = (col: string) => {
|
||||
return {
|
||||
color1: {
|
||||
value: new THREE.Color("white"),
|
||||
},
|
||||
color2: {
|
||||
value: new THREE.Color(col),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const [blueUniforms, cyanUniforms, whiteUniforms] = [
|
||||
"blue",
|
||||
"cyan",
|
||||
"gray",
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
].map((color: string) => useMemo(() => uniformConstructor(color), [color]));
|
||||
|
||||
const [
|
||||
posesBlueFromRight,
|
||||
posesBlueFromLeft,
|
||||
posesCyanFromRight,
|
||||
posesCyanFromLeft,
|
||||
posesWhiteFromRight,
|
||||
posesWhiteFromLeft,
|
||||
] = [5, 5, 5, 5, 5, 5].map((x) =>
|
||||
Array.from({ length: x }, () => [
|
||||
lcgInstance() / 1000000000,
|
||||
lcgInstance() / 1000000000 - 1,
|
||||
lcgInstance() / 1000000000,
|
||||
])
|
||||
);
|
||||
|
||||
const [
|
||||
blueFromRightRef,
|
||||
blueFromLeftRef,
|
||||
cyanFromRightRef,
|
||||
cyanFromLeftRef,
|
||||
whiteFromRightRef,
|
||||
whiteFromLeftRef,
|
||||
] = [
|
||||
posesBlueFromRight,
|
||||
posesBlueFromLeft,
|
||||
posesCyanFromRight,
|
||||
posesCyanFromLeft,
|
||||
posesWhiteFromRight,
|
||||
posesWhiteFromLeft,
|
||||
].map((poses) =>
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useRef<RefObject<THREE.Object3D>[]>(
|
||||
poses.map(() => createRef<THREE.Object3D>())
|
||||
)
|
||||
);
|
||||
|
||||
const [introPosesBlue, introPosesCyan, introPosesWhite] = [
|
||||
80,
|
||||
80,
|
||||
60,
|
||||
].map((x) =>
|
||||
Array.from({ length: x }, () => [
|
||||
lcgInstance() / 1000000050,
|
||||
lcgInstance() / 100000099,
|
||||
lcgInstance() / 1000000050,
|
||||
])
|
||||
);
|
||||
|
||||
const [introBlueRef, introCyanRef, introWhiteRef] = [
|
||||
introPosesBlue,
|
||||
introPosesCyan,
|
||||
introPosesWhite,
|
||||
].map((poses) =>
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useRef<RefObject<THREE.Object3D>[]>(
|
||||
poses.map(() => createRef<THREE.Object3D>())
|
||||
)
|
||||
);
|
||||
|
||||
const fromRightStarRefsAndInitialPoses: StarRefsAndInitialPoses = [
|
||||
[blueFromRightRef, posesBlueFromRight],
|
||||
[cyanFromRightRef, posesCyanFromRight],
|
||||
[whiteFromRightRef, posesWhiteFromRight],
|
||||
];
|
||||
|
||||
const fromLeftStarRefsAndInitialPoses: StarRefsAndInitialPoses = [
|
||||
[blueFromLeftRef, posesBlueFromLeft],
|
||||
[cyanFromLeftRef, posesCyanFromLeft],
|
||||
[whiteFromLeftRef, posesWhiteFromLeft],
|
||||
];
|
||||
|
||||
const starSpeeds = Array.from(
|
||||
{ length: 60 },
|
||||
() => lcgInstance() / 100000000000 + 0.03
|
||||
);
|
||||
|
||||
useFrame(() => {
|
||||
if (introStarfieldVisible) {
|
||||
introStarfieldGroupRef.current!.position.y += 0.2;
|
||||
}
|
||||
if (mainStarfieldVisible) {
|
||||
// planes (stars) coming from right move to positive X and negative Z direction
|
||||
fromRightStarRefsAndInitialPoses.forEach((el) => {
|
||||
el[0].current.forEach(
|
||||
(posRef: RefObject<THREE.Object3D>, idx: number) => {
|
||||
if (posRef.current!.position.x < -1) {
|
||||
posRef.current!.position.x = el[1][idx][0] + 6;
|
||||
posRef.current!.position.z = el[1][idx][2] - 2.5;
|
||||
}
|
||||
posRef.current!.position.x -=
|
||||
starSpeeds[idx] + starfieldState.starfieldBoostVal.get();
|
||||
posRef.current!.position.z +=
|
||||
0.035 + starfieldState.starfieldBoostVal.get() * 0.5;
|
||||
}
|
||||
);
|
||||
});
|
||||
// the ones that are coming from left move to negative X and Z
|
||||
fromLeftStarRefsAndInitialPoses.forEach((el) => {
|
||||
el[0].current.forEach(
|
||||
(posRef: RefObject<THREE.Object3D>, idx: number) => {
|
||||
if (posRef.current!.position.x > 3) {
|
||||
posRef.current!.position.x = el[1][idx][0] - 9;
|
||||
posRef.current!.position.z = el[1][idx][2] - 0.5;
|
||||
} else {
|
||||
posRef.current!.position.x +=
|
||||
starSpeeds[idx] + starfieldState.starfieldBoostVal.get();
|
||||
posRef.current!.position.z +=
|
||||
0.015 + starfieldState.starfieldBoostVal.get() * 0.5;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const mainStarfieldObjects = [
|
||||
{
|
||||
starPoses: posesBlueFromRight,
|
||||
ref: blueFromRightRef,
|
||||
rotation: [1.7, 0, 1],
|
||||
positionSpecifier: [6, 0, -2.5],
|
||||
uniform: blueUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: posesBlueFromLeft,
|
||||
ref: blueFromLeftRef,
|
||||
rotation: [1.7, 0, -1.2],
|
||||
positionSpecifier: [-2.4, -0.5, 2],
|
||||
uniform: blueUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: posesCyanFromRight,
|
||||
ref: cyanFromRightRef,
|
||||
rotation: [1.7, 0, 1],
|
||||
positionSpecifier: [6, 0, -2.5],
|
||||
uniform: cyanUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: posesCyanFromLeft,
|
||||
ref: cyanFromLeftRef,
|
||||
rotation: [1.7, 0, -1.2],
|
||||
positionSpecifier: [-1.3, 0, 2.5],
|
||||
uniform: cyanUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: posesWhiteFromLeft,
|
||||
ref: whiteFromLeftRef,
|
||||
rotation: [1.7, 0, -1.2],
|
||||
positionSpecifier: [-1.3, 0.5, 2.3],
|
||||
uniform: whiteUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: posesWhiteFromRight,
|
||||
ref: whiteFromRightRef,
|
||||
rotation: [1.7, 0, 1],
|
||||
positionSpecifier: [-1.3, 0.5, -2.5],
|
||||
uniform: whiteUniforms,
|
||||
},
|
||||
];
|
||||
|
||||
const introStarfieldObjects = [
|
||||
{
|
||||
starPoses: introPosesBlue,
|
||||
ref: introBlueRef,
|
||||
uniform: blueUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: introPosesCyan,
|
||||
ref: introCyanRef,
|
||||
uniform: cyanUniforms,
|
||||
},
|
||||
{
|
||||
starPoses: introPosesWhite,
|
||||
ref: introWhiteRef,
|
||||
uniform: whiteUniforms,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<a.group
|
||||
ref={introStarfieldGroupRef}
|
||||
position={[-2, -35, -3.2]}
|
||||
rotation={[0, 0, 0]}
|
||||
visible={introStarfieldVisible}
|
||||
>
|
||||
{introStarfieldObjects.map((obj: IntroStarfieldObjectData) =>
|
||||
obj.starPoses.map((pos: number[], idx: number) => {
|
||||
return (
|
||||
<mesh
|
||||
ref={obj.ref.current[idx]}
|
||||
scale={[0.005, 2, 0.005]}
|
||||
position={[pos[0], pos[1], pos[2]]}
|
||||
key={pos[0]}
|
||||
renderOrder={-1}
|
||||
>
|
||||
<boxBufferGeometry attach="geometry" />
|
||||
<shaderMaterial
|
||||
attach="material"
|
||||
uniforms={obj.uniform}
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
side={THREE.DoubleSide}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</a.group>
|
||||
<a.group
|
||||
position={[-0.7, 0, -5]}
|
||||
rotation={[0, 0, 0]}
|
||||
position-y={-1}
|
||||
visible={mainStarfieldVisible}
|
||||
>
|
||||
{mainStarfieldObjects.map((obj: StarfieldObjectData) =>
|
||||
obj.starPoses.map((pos: number[], idx: number) => {
|
||||
return (
|
||||
<mesh
|
||||
ref={obj.ref.current[idx]}
|
||||
position={[
|
||||
pos[0] + obj.positionSpecifier[0],
|
||||
pos[1] + obj.positionSpecifier[1],
|
||||
pos[2] + obj.positionSpecifier[2],
|
||||
]}
|
||||
rotation={obj.rotation as [number, number, number]}
|
||||
scale={[0.01, 2, 0.01]}
|
||||
renderOrder={-1}
|
||||
key={pos[0]}
|
||||
>
|
||||
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
|
||||
<a.shaderMaterial
|
||||
attach="material"
|
||||
uniforms={obj.uniform}
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</a.group>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default Starfield;
|
80
src/components/MainScene/Starfield/Star.tsx
Normal file
80
src/components/MainScene/Starfield/Star.tsx
Normal file
|
@ -0,0 +1,80 @@
|
|||
import React, { useRef } from "react";
|
||||
import { a } from "@react-spring/three";
|
||||
import * as THREE from "three";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
|
||||
type StarProps = {
|
||||
position: number[];
|
||||
color: string;
|
||||
};
|
||||
|
||||
const Star = (props: StarProps) => {
|
||||
const uniformConstructor = (col: string) => {
|
||||
return {
|
||||
color1: {
|
||||
value: new THREE.Color("white"),
|
||||
},
|
||||
color2: {
|
||||
value: new THREE.Color(col),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
`;
|
||||
|
||||
const starRef = useRef<THREE.Object3D>();
|
||||
|
||||
const amp = useRef(Math.random() / 10);
|
||||
|
||||
useFrame(() => {
|
||||
if (starRef.current) {
|
||||
if (starRef.current.position.y > 4) {
|
||||
starRef.current.position.y = props.position[1];
|
||||
}
|
||||
starRef.current.position.y += (0.01 + amp.current);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<mesh
|
||||
position={props.position as [number, number, number]}
|
||||
scale={[0.01, 2, 0.01]}
|
||||
renderOrder={-1}
|
||||
ref={starRef}
|
||||
>
|
||||
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
|
||||
<a.shaderMaterial
|
||||
attach="material"
|
||||
fragmentShader={fragmentShader}
|
||||
vertexShader={vertexShader}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
uniforms={uniformConstructor(props.color)}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
};
|
||||
|
||||
export default Star;
|
57
src/components/MainScene/Starfield/Starfield.tsx
Normal file
57
src/components/MainScene/Starfield/Starfield.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
import React from "react";
|
||||
import Star from "./Star";
|
||||
|
||||
type StarfieldProps = {
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
const Starfield = (props: StarfieldProps) => {
|
||||
const LCG = (a: number, c: number, m: number, s: number) => () =>
|
||||
(s = (s * a + c) % m);
|
||||
|
||||
const lcgInstance = LCG(1664525, 1013904223, 2 ** 32, 2);
|
||||
|
||||
const [
|
||||
posesBlueFromRight,
|
||||
posesBlueFromLeft,
|
||||
posesCyanFromRight,
|
||||
posesCyanFromLeft,
|
||||
posesWhiteFromRight,
|
||||
posesWhiteFromLeft,
|
||||
] = [5, 5, 5, 5, 5, 5].map((x) =>
|
||||
Array.from({ length: x }, () => [
|
||||
lcgInstance() / 1000000000,
|
||||
lcgInstance() / 10000000000 - 10,
|
||||
lcgInstance() / 1000000000,
|
||||
])
|
||||
);
|
||||
|
||||
return (
|
||||
<group position={[0, -1, 2]} visible={props.visible}>
|
||||
<group rotation={[0, 0.75, Math.PI / 2]} position={[-0.7, -1, -5]}>
|
||||
{posesBlueFromLeft.map((poses, idx) => (
|
||||
<Star position={poses} color={"blue"} key={idx} />
|
||||
))}
|
||||
{posesWhiteFromLeft.map((poses, idx) => (
|
||||
<Star position={poses} color={"white"} key={idx} />
|
||||
))}
|
||||
{posesCyanFromLeft.map((poses, idx) => (
|
||||
<Star position={poses} color={"cyan"} key={idx} />
|
||||
))}
|
||||
</group>
|
||||
<group rotation={[0, 2.5, Math.PI / 2]} position={[-0.7, -1, -1]}>
|
||||
{posesBlueFromRight.map((poses, idx) => (
|
||||
<Star position={poses} color={"blue"} key={idx} />
|
||||
))}
|
||||
{posesWhiteFromRight.map((poses, idx) => (
|
||||
<Star position={poses} color={"white"} key={idx} />
|
||||
))}
|
||||
{posesCyanFromRight.map((poses, idx) => (
|
||||
<Star position={poses} color={"cyan"} key={idx} />
|
||||
))}
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default Starfield;
|
|
@ -15,35 +15,41 @@ const SubsceneManager = (props: StateManagerProps) => {
|
|||
return {
|
||||
action: setMainSubscene,
|
||||
value: "site",
|
||||
delay: 0,
|
||||
};
|
||||
case "toggle_level_selection":
|
||||
return {
|
||||
action: setMainSubscene,
|
||||
value: "level_selection",
|
||||
delay: 0,
|
||||
};
|
||||
case "toggle_pause":
|
||||
return {
|
||||
action: setMainSubscene,
|
||||
value: "pause",
|
||||
delay: 0,
|
||||
};
|
||||
case "pause_exit_select":
|
||||
return {
|
||||
action: setMainSubscene,
|
||||
value: "site",
|
||||
delay: 1800,
|
||||
};
|
||||
case "authorize_user_back":
|
||||
case "load_data_no_select":
|
||||
return {
|
||||
action: setBootSubscene,
|
||||
value: "main_menu",
|
||||
delay: 0,
|
||||
};
|
||||
case "authorize_user_select":
|
||||
return {
|
||||
action: setBootSubscene,
|
||||
value: "authorize_user",
|
||||
delay: 0,
|
||||
};
|
||||
case "load_data_select":
|
||||
return { action: setBootSubscene, value: "load_data" };
|
||||
return { action: setBootSubscene, value: "load_data", delay: 0 };
|
||||
}
|
||||
},
|
||||
[setBootSubscene, setMainSubscene]
|
||||
|
@ -56,7 +62,9 @@ const SubsceneManager = (props: StateManagerProps) => {
|
|||
const dispatchedObject = dispatchObject(eventAction);
|
||||
|
||||
if (dispatchedObject) {
|
||||
dispatchedObject.action(dispatchedObject.value);
|
||||
setTimeout(() => {
|
||||
dispatchedObject.action(dispatchedObject.value);
|
||||
}, dispatchedObject.delay);
|
||||
}
|
||||
}
|
||||
}, [props.eventState, dispatchObject]);
|
||||
|
|
|
@ -7,7 +7,6 @@ import Preloader from "../components/Preloader";
|
|||
import MainSceneIntro from "../components/MainSceneIntro";
|
||||
import GrayPlanes from "../components/MainScene/GrayPlanes";
|
||||
import MiddleRing from "../components/MainScene/MiddleRing";
|
||||
import Starfield from "../components/MainScene/Starfield";
|
||||
import { useHudStore, useLainStore, useMainSceneStore } from "../store";
|
||||
import GreenTextRenderer from "../components/TextRenderer/GreenTextRenderer";
|
||||
import HUD from "../components/MainScene/HUD";
|
||||
|
@ -15,7 +14,8 @@ import YellowOrb from "../components/MainScene/YellowOrb";
|
|||
import ActiveLevelNodes from "../components/MainScene/ActiveLevelNodes";
|
||||
import YellowTextRenderer from "../components/TextRenderer/YellowTextRenderer";
|
||||
import LevelSelection from "../components/MainScene/LevelSelection";
|
||||
import Pause from "../components/MainScene/Pause";
|
||||
import Pause from "../components/MainScene/PauseSubscene/Pause";
|
||||
import Starfield from "../components/MainScene/Starfield/Starfield";
|
||||
|
||||
const MainScene = () => {
|
||||
const currentSubscene = useMainSceneStore((state) => state.subscene);
|
||||
|
@ -35,18 +35,18 @@ const MainScene = () => {
|
|||
<Suspense fallback={null}>
|
||||
<MainSceneIntro />
|
||||
<a.group>
|
||||
<Preloader />
|
||||
{/*<Preloader />*/}
|
||||
<Site />
|
||||
<ActiveLevelNodes />
|
||||
<HUD visible={!isPaused} />
|
||||
<GreenTextRenderer visible={!isPaused} />
|
||||
<YellowTextRenderer visible={!isPaused} />
|
||||
<YellowOrb visible={!isPaused} />
|
||||
<Starfield />
|
||||
<GrayPlanes visible={!isPaused} />
|
||||
<MiddleRing />
|
||||
<LevelSelection />
|
||||
<Pause visible={isPaused} />
|
||||
<Starfield visible={!isPaused}/>
|
||||
<OrbitControls />
|
||||
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />
|
||||
<pointLight color={0x7f7f7f} position={[0, 10, 0]} intensity={1.5} />
|
||||
|
|
Loading…
Reference in a new issue