mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
adding level selection
This commit is contained in:
parent
46d9c421c8
commit
00de2883a8
7 changed files with 205 additions and 30 deletions
152
src/components/MainScene/LevelSelection.tsx
Normal file
152
src/components/MainScene/LevelSelection.tsx
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
import React, { useCallback, useEffect, useMemo } from "react";
|
||||||
|
import level_selection_font from "../../static/sprite/select_level_font.png";
|
||||||
|
import verticalHud from "../../static/sprite/select_level_hud_vertical.png";
|
||||||
|
import horizontalHud from "../../static/sprite/select_level_hud_horizontal.png";
|
||||||
|
import levelSelectionText from "../../static/sprite/select_level_text.png";
|
||||||
|
import upArrow from "../../static/sprite/select_level_up_arrow.png";
|
||||||
|
import downArrow from "../../static/sprite/select_level_down_arrow.png";
|
||||||
|
import { useLevelSelectionStore } from "../../store";
|
||||||
|
import { useLoader } from "react-three-fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { a, useSpring } from "@react-spring/three";
|
||||||
|
|
||||||
|
const LevelSelection = () => {
|
||||||
|
const levelSelectionFontTex = useLoader(
|
||||||
|
THREE.TextureLoader,
|
||||||
|
level_selection_font
|
||||||
|
);
|
||||||
|
const verticalHudTex = useLoader(THREE.TextureLoader, verticalHud);
|
||||||
|
const horizontalHudTex = useLoader(THREE.TextureLoader, horizontalHud);
|
||||||
|
const levelSelectionTextTex = useLoader(
|
||||||
|
THREE.TextureLoader,
|
||||||
|
levelSelectionText
|
||||||
|
);
|
||||||
|
const upArrowTex = useLoader(THREE.TextureLoader, upArrow);
|
||||||
|
const downArrowTex = useLoader(THREE.TextureLoader, downArrow);
|
||||||
|
|
||||||
|
const selectedLevelIdx = useLevelSelectionStore(
|
||||||
|
(state) => state.selectedLevelIdx
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedLevel = useLevelSelectionStore(
|
||||||
|
useCallback((state) => state.availableLevels[selectedLevelIdx], [
|
||||||
|
selectedLevelIdx,
|
||||||
|
])
|
||||||
|
)
|
||||||
|
.toString()
|
||||||
|
.padStart(2, "0");
|
||||||
|
|
||||||
|
const levelSelectionToggled = useLevelSelectionStore(
|
||||||
|
(state) => state.levelSelectionToggled
|
||||||
|
);
|
||||||
|
|
||||||
|
const { levelSelectionToggle } = useSpring({
|
||||||
|
levelSelectionToggle: levelSelectionToggled,
|
||||||
|
config: { duration: 500 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const verticalHudPosY = levelSelectionToggle.to([0, 1], [-2.5, 0]);
|
||||||
|
const horizontalHudPosX = levelSelectionToggle.to([0, 1], [-4, -0.6]);
|
||||||
|
|
||||||
|
const generateGeom = useCallback((number: number) => {
|
||||||
|
const geometry = new THREE.PlaneBufferGeometry();
|
||||||
|
|
||||||
|
const uvAttribute = geometry.attributes.uv;
|
||||||
|
|
||||||
|
for (let i = 0; i < uvAttribute.count; i++) {
|
||||||
|
let u = uvAttribute.getX(i);
|
||||||
|
let v = uvAttribute.getY(i);
|
||||||
|
|
||||||
|
u = (u * 22) / 240 + number / 10;
|
||||||
|
|
||||||
|
uvAttribute.setXY(i, u, v);
|
||||||
|
}
|
||||||
|
return geometry;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<a.group position-y={verticalHudPosY} renderOrder={5}>
|
||||||
|
<mesh
|
||||||
|
scale={[0.3, 0.4, 0]}
|
||||||
|
position={[0.95, 0, 0]}
|
||||||
|
renderOrder={5}
|
||||||
|
geometry={generateGeom(parseInt(selectedLevel[0]))}
|
||||||
|
>
|
||||||
|
<meshBasicMaterial
|
||||||
|
map={levelSelectionFontTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
<mesh
|
||||||
|
scale={[0.3, 0.4, 0]}
|
||||||
|
position={[1.23, 0, 0]}
|
||||||
|
renderOrder={5}
|
||||||
|
geometry={generateGeom(parseInt(selectedLevel[1]))}
|
||||||
|
>
|
||||||
|
<meshBasicMaterial
|
||||||
|
map={levelSelectionFontTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
|
||||||
|
<sprite scale={[0.65, 3, 0]} position={[1.1, -0.8, 0]} renderOrder={4}>
|
||||||
|
<spriteMaterial
|
||||||
|
map={verticalHudTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</sprite>
|
||||||
|
<sprite scale={[0.5, 0.12, 0]} position={[1.1, 0.3, 0]} renderOrder={4}>
|
||||||
|
<spriteMaterial
|
||||||
|
map={levelSelectionTextTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</sprite>
|
||||||
|
<sprite
|
||||||
|
scale={[0.3, 0.15, 0]}
|
||||||
|
position={[1.1, -0.35, 0]}
|
||||||
|
renderOrder={4}
|
||||||
|
>
|
||||||
|
<spriteMaterial
|
||||||
|
map={downArrowTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</sprite>
|
||||||
|
<sprite scale={[0.3, 0.15, 0]} position={[1.1, 0.5, 0]} renderOrder={4}>
|
||||||
|
<spriteMaterial
|
||||||
|
map={upArrowTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</sprite>
|
||||||
|
</a.group>
|
||||||
|
|
||||||
|
<a.sprite
|
||||||
|
scale={[3, 0.3, 0]}
|
||||||
|
position={[-0.6, 0, 0]}
|
||||||
|
renderOrder={4}
|
||||||
|
position-x={horizontalHudPosX}
|
||||||
|
>
|
||||||
|
<spriteMaterial
|
||||||
|
map={horizontalHudTex}
|
||||||
|
attach="material"
|
||||||
|
transparent={true}
|
||||||
|
depthTest={false}
|
||||||
|
/>
|
||||||
|
</a.sprite>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LevelSelection;
|
|
@ -1,14 +0,0 @@
|
||||||
import React, { memo } from "react";
|
|
||||||
|
|
||||||
const Lights = memo(() => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />
|
|
||||||
<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} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Lights;
|
|
|
@ -37,6 +37,7 @@ const getKeyCodeAssociation = (keyCode: number): string => {
|
||||||
39: "right", // right arrow
|
39: "right", // right arrow
|
||||||
88: "select", // x key
|
88: "select", // x key
|
||||||
90: "back", // z key
|
90: "back", // z key
|
||||||
|
69: "toggle_level_selection", // e key
|
||||||
};
|
};
|
||||||
return keyCodeAssocs[keyCode as keyof typeof keyCodeAssocs];
|
return keyCodeAssocs[keyCode as keyof typeof keyCodeAssocs];
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect } from "react";
|
||||||
import { StateManagerProps } from "./EventManager";
|
import { StateManagerProps } from "./EventManager";
|
||||||
import { useLevelStore } from "../../store";
|
import { useLevelSelectionStore, useLevelStore } from "../../store";
|
||||||
|
|
||||||
const LevelManager = (props: StateManagerProps) => {
|
const LevelManager = (props: StateManagerProps) => {
|
||||||
const setActiveLevel = useLevelStore((state) => state.setActiveLevel);
|
const setActiveLevel = useLevelStore((state) => state.setActiveLevel);
|
||||||
|
const toggleLevelSelection = useLevelSelectionStore(
|
||||||
|
(state) => state.toggleLevelSelection
|
||||||
|
);
|
||||||
|
|
||||||
const dispatchObject = useCallback(
|
const dispatchObject = useCallback(
|
||||||
(event: string, newLevel: string) => {
|
(event: string, newLevel: string) => {
|
||||||
|
@ -14,9 +17,13 @@ const LevelManager = (props: StateManagerProps) => {
|
||||||
action: setActiveLevel,
|
action: setActiveLevel,
|
||||||
value: newLevel,
|
value: newLevel,
|
||||||
};
|
};
|
||||||
|
case "toggle_level_selection":
|
||||||
|
return {
|
||||||
|
action: toggleLevelSelection,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setActiveLevel]
|
[setActiveLevel, toggleLevelSelection]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -26,7 +33,10 @@ const LevelManager = (props: StateManagerProps) => {
|
||||||
const dispatchedObject = dispatchObject(eventAction, newLevel);
|
const dispatchedObject = dispatchObject(eventAction, newLevel);
|
||||||
|
|
||||||
if (dispatchedObject) {
|
if (dispatchedObject) {
|
||||||
dispatchedObject.action(dispatchedObject.value);
|
(dispatchedObject.action as any).apply(
|
||||||
|
null,
|
||||||
|
dispatchedObject.value as any
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [props.eventState, dispatchObject]);
|
}, [props.eventState, dispatchObject]);
|
||||||
|
|
|
@ -113,6 +113,9 @@ const handleMainSceneEvent = (gameContext: any) => {
|
||||||
newScene = "sskn";
|
newScene = "sskn";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "toggle_level_selection":
|
||||||
|
return { event: "toggle_level_selection" };
|
||||||
}
|
}
|
||||||
|
|
||||||
const newActiveNodeId =
|
const newActiveNodeId =
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { OrbitControls } from "@react-three/drei";
|
||||||
import React, { Suspense, useEffect } from "react";
|
import React, { Suspense, useEffect } from "react";
|
||||||
import Site from "../components/MainScene/Site";
|
import Site from "../components/MainScene/Site";
|
||||||
import Lain from "../components/MainScene/Lain";
|
import Lain from "../components/MainScene/Lain";
|
||||||
import Lights from "../components/MainScene/Lights";
|
|
||||||
import Preloader from "../components/Preloader";
|
import Preloader from "../components/Preloader";
|
||||||
import MainSceneIntro from "../components/MainSceneIntro";
|
import MainSceneIntro from "../components/MainSceneIntro";
|
||||||
import GrayPlanes from "../components/MainScene/GrayPlanes";
|
import GrayPlanes from "../components/MainScene/GrayPlanes";
|
||||||
|
@ -15,6 +14,7 @@ import HUD from "../components/MainScene/HUD";
|
||||||
import YellowOrb from "../components/MainScene/YellowOrb";
|
import YellowOrb from "../components/MainScene/YellowOrb";
|
||||||
import ActiveLevelNodes from "../components/MainScene/ActiveLevelNodes";
|
import ActiveLevelNodes from "../components/MainScene/ActiveLevelNodes";
|
||||||
import YellowTextRenderer from "../components/TextRenderer/YellowTextRenderer";
|
import YellowTextRenderer from "../components/TextRenderer/YellowTextRenderer";
|
||||||
|
import LevelSelection from "../components/MainScene/LevelSelection";
|
||||||
|
|
||||||
const MainScene = () => {
|
const MainScene = () => {
|
||||||
const setLainMoveState = useLainStore((state) => state.setLainMoveState);
|
const setLainMoveState = useLainStore((state) => state.setLainMoveState);
|
||||||
|
@ -30,18 +30,22 @@ const MainScene = () => {
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<MainSceneIntro />
|
<MainSceneIntro />
|
||||||
<a.group>
|
<a.group>
|
||||||
<Preloader />
|
{/*<Preloader />*/}
|
||||||
<Site />
|
{/*<Site />*/}
|
||||||
<ActiveLevelNodes />
|
{/*<ActiveLevelNodes />*/}
|
||||||
<HUD />
|
{/*<HUD />*/}
|
||||||
<TextRenderer />
|
{/*<TextRenderer />*/}
|
||||||
<YellowTextRenderer />
|
{/*<YellowTextRenderer />*/}
|
||||||
<YellowOrb />
|
{/*<YellowOrb />*/}
|
||||||
<Starfield />
|
{/*<Starfield />*/}
|
||||||
<GrayPlanes />
|
{/*<GrayPlanes />*/}
|
||||||
<Lights />
|
{/*<MiddleRing />*/}
|
||||||
<MiddleRing />
|
<LevelSelection />
|
||||||
<OrbitControls />
|
<OrbitControls />
|
||||||
|
<pointLight color={0xffffff} position={[0, 0, 7]} intensity={1} />
|
||||||
|
<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} />
|
||||||
</a.group>
|
</a.group>
|
||||||
<Lain />
|
<Lain />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
21
src/store.ts
21
src/store.ts
|
@ -3,6 +3,14 @@ import { combine } from "zustand/middleware";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import authorize_user_letters from "./resources/authorize_user_letters.json";
|
import authorize_user_letters from "./resources/authorize_user_letters.json";
|
||||||
|
|
||||||
|
type LevelSelectionState = {
|
||||||
|
availableLevels: number[];
|
||||||
|
selectedLevelIdx: number;
|
||||||
|
levelSelectionToggled: number;
|
||||||
|
setSelectedLevelIdx: (to: number) => void;
|
||||||
|
toggleLevelSelection: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
type SceneState = {
|
type SceneState = {
|
||||||
currentScene: string;
|
currentScene: string;
|
||||||
setScene: (to: string) => void;
|
setScene: (to: string) => void;
|
||||||
|
@ -381,7 +389,7 @@ export const useSSknStore = create<SSknState>((set) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useSceneStore = create<SceneState>((set) => ({
|
export const useSceneStore = create<SceneState>((set) => ({
|
||||||
currentScene: "polytan",
|
currentScene: "main",
|
||||||
setScene: (to) => set(() => ({ currentScene: to })),
|
setScene: (to) => set(() => ({ currentScene: to })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -457,3 +465,14 @@ export const useGateStore = create<GateState>((set) => ({
|
||||||
gateLvl: 4,
|
gateLvl: 4,
|
||||||
incrementGateLvl: () => set((state) => ({ gateLvl: state.gateLvl + 1 })),
|
incrementGateLvl: () => set((state) => ({ gateLvl: state.gateLvl + 1 })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const useLevelSelectionStore = create<LevelSelectionState>((set) => ({
|
||||||
|
availableLevels: Array.from({ length: 24 }, (x, i) => i + 1),
|
||||||
|
selectedLevelIdx: 23,
|
||||||
|
levelSelectionToggled: 0,
|
||||||
|
setSelectedLevelIdx: (to) => set(() => ({ selectedLevelIdx: to })),
|
||||||
|
toggleLevelSelection: () =>
|
||||||
|
set((state) => ({
|
||||||
|
levelSelectionToggled: Number(!state.levelSelectionToggled),
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
Loading…
Reference in a new issue