added prompt, and word selection node not found handling

This commit is contained in:
ad044 2021-02-07 19:12:19 +04:00
parent bc018e964d
commit 8f303e455a
19 changed files with 658 additions and 339 deletions

View file

@ -14,92 +14,93 @@ type BootLoadDataProps = {
};
const BootLoadData = (props: BootLoadDataProps) => {
const loadDataUnderlineTex = useLoader(
THREE.TextureLoader,
loadDataUnderline
);
const loadDataQuestionContainerTex = useLoader(
THREE.TextureLoader,
loadDataQuestionContainer
);
const loadDataAnswerContainerTex = useLoader(
THREE.TextureLoader,
loadDataAnswerContainer
);
const areYouSureTex = useLoader(THREE.TextureLoader, areYouSure);
const yesTex = useLoader(THREE.TextureLoader, yes);
const noTex = useLoader(THREE.TextureLoader, no);
return (
<>
{props.visible ? (
<>
<sprite scale={[4.1, 0.3, 0]} renderOrder={2} position={[0, 0.2, 0]}>
<spriteMaterial
map={loadDataQuestionContainerTex}
attach="material"
transparent={true}
opacity={0.6}
/>
</sprite>
<sprite scale={[2, 0.24, 0]} renderOrder={3} position={[0, 0.19, 0]}>
<spriteMaterial
map={areYouSureTex}
attach="material"
transparent={true}
/>
</sprite>
<sprite
scale={[0.5, 0.19, 0]}
renderOrder={3}
position={[-1.2, -0.2, 0]}
>
<spriteMaterial map={yesTex} attach="material" transparent={true} />
</sprite>
<sprite
scale={[0.7, 0.3, 0]}
renderOrder={2}
position={
props.activeBootElement === "load_data_yes"
? [-1.2, -0.2, 0]
: [1.2, -0.2, 0]
}
>
<spriteMaterial
map={loadDataAnswerContainerTex}
attach="material"
transparent={true}
/>
</sprite>
<sprite
scale={[0.4, 0.19, 0]}
renderOrder={3}
position={[1.2, -0.2, 0]}
>
<spriteMaterial map={noTex} attach="material" transparent={true} />
</sprite>
<sprite
scale={[3.5, 0.01, 0]}
position={[-0.5, -1.15, 0]}
renderOrder={2}
>
<spriteMaterial
map={loadDataUnderlineTex}
attach="material"
transparent={true}
/>
</sprite>
</>
) : (
<></>
)}
</>
);
// const loadDataUnderlineTex = useLoader(
// THREE.TextureLoader,
// loadDataUnderline
// );
// const loadDataQuestionContainerTex = useLoader(
// THREE.TextureLoader,
// loadDataQuestionContainer
// );
// const loadDataAnswerContainerTex = useLoader(
// THREE.TextureLoader,
// loadDataAnswerContainer
// );
// const areYouSureTex = useLoader(THREE.TextureLoader, areYouSure);
// const yesTex = useLoader(THREE.TextureLoader, yes);
// const noTex = useLoader(THREE.TextureLoader, no);
//
// return (
// <>
// {props.visible ? (
// <>
// <sprite scale={[4.1, 0.3, 0]} renderOrder={2} position={[0, 0.2, 0]}>
// <spriteMaterial
// map={loadDataQuestionContainerTex}
// attach="material"
// transparent={true}
// opacity={0.6}
// />
// </sprite>
//
// <sprite scale={[2, 0.24, 0]} renderOrder={3} position={[0, 0.19, 0]}>
// <spriteMaterial
// map={areYouSureTex}
// attach="material"
// transparent={true}
// />
// </sprite>
//
// <sprite
// scale={[0.5, 0.19, 0]}
// renderOrder={3}
// position={[-1.2, -0.2, 0]}
// >
// <spriteMaterial map={yesTex} attach="material" transparent={true} />
// </sprite>
//
// <sprite
// scale={[0.7, 0.3, 0]}
// renderOrder={2}
// position={
// props.activeBootElement === "load_data_yes"
// ? [-1.2, -0.2, 0]
// : [1.2, -0.2, 0]
// }
// >
// <spriteMaterial
// map={loadDataAnswerContainerTex}
// attach="material"
// transparent={true}
// />
// </sprite>
//
// <sprite
// scale={[0.4, 0.19, 0]}
// renderOrder={3}
// position={[1.2, -0.2, 0]}
// >
// <spriteMaterial map={noTex} attach="material" transparent={true} />
// </sprite>
//
// <sprite
// scale={[3.5, 0.01, 0]}
// position={[-0.5, -1.15, 0]}
// renderOrder={2}
// >
// <spriteMaterial
// map={loadDataUnderlineTex}
// attach="material"
// transparent={true}
// />
// </sprite>
// </>
// ) : (
// <></>
// )}
// </>
// );
return <></>;
};
export default BootLoadData;

View file

@ -22,6 +22,7 @@ import handleMainSceneEvent from "../core/scene-keypress-handlers/handleMainKeyP
import gameLoader from "../core/setters/gameLoader";
import gameSaver from "../core/setters/gameSaver";
import progressManager from "../core/setters/progressManager";
import promptManager from "../core/setters/promptManager";
const KeyPressHandler = () => {
const mediaSceneSetters = useMemo(
@ -32,6 +33,7 @@ const KeyPressHandler = () => {
levelManager,
siteManager,
progressManager,
mainSubsceneManager,
],
[]
);
@ -52,6 +54,7 @@ const KeyPressHandler = () => {
gameLoader,
gameSaver,
progressManager,
promptManager,
],
[]
);
@ -92,6 +95,7 @@ const KeyPressHandler = () => {
};
case "gate":
case "polytan":
case "about":
return {
action: () => useStore.setState({ currentScene: "main" }),
};

View file

@ -130,6 +130,7 @@ const HUD = memo(() => {
if (
!(scene === "main" && prevData?.scene === "main") ||
(subscene === "site" && prevData?.subscene === "pause") ||
(subscene === "site" && prevData?.subscene === "not_found") ||
subscene === "pause"
) {
// set to final pos instantly

View file

@ -0,0 +1,48 @@
import React from "react";
import notFound from "../../static/sprite/not_found.png";
import notFoundLof from "../../static/sprite/not_found_lof.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
type NotFoundProps = {
visible: boolean;
};
const NotFound = (props: NotFoundProps) => {
const notFoundTex = useLoader(THREE.TextureLoader, notFound);
const notFoundLofTex = useLoader(THREE.TextureLoader, notFoundLof);
return (
<>
{props.visible && (
<>
<sprite
scale={[1, 0.25, 0]}
renderOrder={106}
position={[-1, -0.05, 0]}
>
<spriteMaterial
attach="material"
map={notFoundLofTex}
depthTest={false}
/>
</sprite>
<sprite
scale={[4.1, 0.6, 0]}
renderOrder={105}
position={[0, -0.15, 0]}
>
<spriteMaterial
attach="material"
map={notFoundTex}
depthTest={false}
/>
</sprite>
</>
)}
</>
);
};
export default NotFound;

View file

@ -0,0 +1,41 @@
import React, { useRef } from "react";
import aboutBg from "../../../static/sprite/about_background.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../../store";
const About = () => {
const setShowingAbout = useStore((state) => state.setShowingAbout);
const aboutBgTex = useLoader(THREE.TextureLoader, aboutBg);
const bgRef = useRef<THREE.Sprite>();
// todo im not sure where the other bg file is located,
// the one here is just the text, in the original game there's another one
useFrame(() => {
if (bgRef.current) {
bgRef.current.position.y += 0.03;
if (Math.round(bgRef.current.position.y) === 14) {
setShowingAbout(false);
}
}
});
return (
<>
<sprite renderOrder={199} scale={[100, 100, 0]}>
<spriteMaterial attach="material" color={0x000000} depthTest={false} />
</sprite>
<sprite
ref={bgRef}
scale={[10.5 / 2.5, 52.8 / 2.5, 0]}
position={[1.1, -13, 0]}
renderOrder={200}
>
<spriteMaterial attach="material" map={aboutBgTex} depthTest={false} />
</sprite>
</>
);
};
export default About;

View file

@ -4,9 +4,12 @@ import PauseSquare from "./PauseSquare";
import StaticBigLetter from "../../TextRenderer/StaticBigLetter";
import { useStore } from "../../../store";
import { useLoader } from "react-three-fiber";
import About from "./About";
import Prompt from "../../Prompt";
const Pause = () => {
const exit = useStore((state) => state.pauseExitAnimation);
const showingAbout = useStore((state) => state.showingAbout);
const [showActiveComponent, setShowActiveComponent] = useState(false);
const [animation, setAnimation] = useState(false);
const [intro, setIntro] = useState(true);
@ -274,7 +277,6 @@ const Pause = () => {
active={activeComponent === "load"}
/>
))}
{"About".split("").map((letter, idx) => (
<StaticBigLetter
color={idx > 0 ? "yellow" : "orange"}
@ -286,7 +288,6 @@ const Pause = () => {
key={idx}
/>
))}
{"Change".split("").map((letter, idx) => (
<StaticBigLetter
color={idx > 0 ? "yellow" : "orange"}
@ -298,7 +299,6 @@ const Pause = () => {
key={idx}
/>
))}
{"Save".split("").map((letter, idx) => (
<StaticBigLetter
color={idx > 0 ? "yellow" : "orange"}
@ -310,7 +310,6 @@ const Pause = () => {
key={idx}
/>
))}
{"Exit".split("").map((letter, idx) => (
<StaticBigLetter
color={idx > 0 ? "yellow" : "orange"}
@ -322,7 +321,6 @@ const Pause = () => {
active={activeComponent === "exit"}
/>
))}
<group visible={!exit}>
<sprite
position={[0.5, -0.8, 0]}
@ -353,6 +351,10 @@ const Pause = () => {
/>
</mesh>
</group>
{showingAbout && <About />}
<group position={[1, 0.6, 0]} scale={[1.2, 1.2, 0]}>
<Prompt />
</group>
</group>
)}
</>

110
src/components/Prompt.tsx Normal file
View file

@ -0,0 +1,110 @@
import React, { useCallback, useEffect } from "react";
import answerContainer from "../static/sprite/prompt_answer_container.png";
import questionContainer from "../static/sprite/prompt_question_container.png";
import yes from "../static/sprite/prompt_yes.png";
import no from "../static/sprite/prompt_no.png";
import question from "../static/sprite/prompt_question.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../store";
const Prompt = () => {
const promptVisible = useStore((state) => state.promptVisible);
const questionContainerTex = useLoader(
THREE.TextureLoader,
questionContainer
);
const answerContainerTex = useLoader(THREE.TextureLoader, answerContainer);
const questionTex = useLoader(THREE.TextureLoader, question);
const yesTex = useLoader(THREE.TextureLoader, yes);
const noTex = useLoader(THREE.TextureLoader, no);
const activeComponent = useStore(
useCallback(
(state) => state.promptComponentMatrix[state.promptComponentMatrixIdx],
[]
)
);
useEffect(() => {
console.log(promptVisible);
}, [promptVisible]);
return (
<>
{promptVisible && (
<>
<sprite
scale={[4.1, 0.3, 0]}
renderOrder={200}
position={[0, 0.2, 0]}
>
<spriteMaterial
map={questionContainerTex}
attach="material"
transparent={true}
opacity={0.6}
depthTest={false}
/>
</sprite>
<sprite
scale={[2, 0.24, 0]}
renderOrder={200}
position={[0, 0.19, 0]}
>
<spriteMaterial
map={questionTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.5, 0.19, 0]}
renderOrder={200}
position={[-1.2, -0.2, 0]}
>
<spriteMaterial
map={yesTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.7, 0.3, 0]}
renderOrder={199}
position={
activeComponent === "yes" ? [-1.2, -0.2, 0] : [1.2, -0.2, 0]
}
>
<spriteMaterial
map={answerContainerTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.4, 0.19, 0]}
renderOrder={200}
position={[1.2, -0.2, 0]}
>
<spriteMaterial
map={noTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
</>
)}
</>
);
};
export default Prompt;

View file

@ -100,6 +100,7 @@ const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
useEffect(() => {
if (
subscene === "pause" ||
(subscene === "site" && prevData?.subscene === "not_found") ||
(subscene === "site" && prevData?.subscene === "pause")
)
return;

View file

@ -3,7 +3,7 @@ import { useStore } from "../../store";
import { a, useTrail } from "@react-spring/three";
import BigLetter from "./BigLetter";
import usePrevious from "../../hooks/usePrevious";
import {getNodeHud} from "../../utils/node-utils";
import { getNodeHud } from "../../utils/node-utils";
const YellowTextRenderer = (props: { visible?: boolean }) => {
const activeNode = useStore((state) => state.activeNode);
@ -22,6 +22,7 @@ const YellowTextRenderer = (props: { visible?: boolean }) => {
useEffect(() => {
const hud = getNodeHud(activeNode.matrixIndices!);
if (subscene === "level_selection") {
setTimeout(() => {
set({ posX: -0.02, posY: 0.005 });

View file

@ -18,273 +18,308 @@ const handleMainSceneEvent = (mainSceneContext: any) => {
level,
keyPress,
ssknLvl,
showingAbout,
promptVisible,
activePromptComponent,
} = mainSceneContext;
switch (subscene) {
case "site":
switch (keyPress) {
case "LEFT":
case "RIGHT": {
const keyPressToLower = keyPress.toLowerCase();
const nodeData = findNode(
activeNode.id,
keyPressToLower,
activeNode.matrixIndices!,
level,
currentSite,
gameProgress,
true
);
if (!nodeData) return;
if (nodeData.didMove) {
if (promptVisible) {
switch (keyPress) {
case "LEFT":
return { event: "prompt_left" };
case "RIGHT":
return { event: "prompt_right" };
case "CIRCLE":
switch (activePromptComponent) {
case "no":
return { event: "exit_prompt" };
case "yes":
return {
event: keyPressToLower === "left" ? `site_left` : "site_right",
siteRotY:
keyPressToLower === "left"
? siteRotY + Math.PI / 4
: siteRotY - Math.PI / 4,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
event: `pause_${activePauseComponent}_select`,
site: currentSite,
};
} else {
return {
event: "change_node",
nodeMatrixIndices: nodeData.matrixIndices,
node: {
...getNodeById(nodeData.node, currentSite),
matrixIndices: nodeData.matrixIndices,
},
};
}
}
case "UP":
case "DOWN": {
const keyPressToLower = keyPress.toLowerCase();
const nodeData = findNode(
activeNode.id,
keyPressToLower,
activeNode.matrixIndices!,
level,
currentSite,
gameProgress,
true
);
}
} else {
switch (subscene) {
case "site":
switch (keyPress) {
case "LEFT":
case "RIGHT": {
const keyPressToLower = keyPress.toLowerCase();
if (!nodeData) return;
const nodeData = findNode(
activeNode.id,
keyPressToLower,
activeNode.matrixIndices!,
level,
currentSite,
gameProgress,
true
);
if (nodeData.didMove) {
return {
event: keyPressToLower === "up" ? "site_up" : "site_down",
level: (keyPressToLower === "up" ? level + 1 : level - 1)
.toString()
.padStart(2, "0"),
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
};
} else {
return {
event: "change_node",
node: {
...getNodeById(nodeData.node, currentSite),
matrixIndices: nodeData.matrixIndices,
},
};
if (!nodeData) return;
if (nodeData.didMove) {
return {
event: keyPressToLower === "left" ? `site_left` : "site_right",
siteRotY:
keyPressToLower === "left"
? siteRotY + Math.PI / 4
: siteRotY - Math.PI / 4,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
};
} else {
return {
event: "change_node",
nodeMatrixIndices: nodeData.matrixIndices,
node: {
...getNodeById(nodeData.node, currentSite),
matrixIndices: nodeData.matrixIndices,
},
};
}
}
}
case "CIRCLE":
const eventAnimation =
Math.random() < 0.4 ? "rip_node" : "throw_node";
case "UP":
case "DOWN": {
const keyPressToLower = keyPress.toLowerCase();
const nodeData = findNode(
activeNode.id,
keyPressToLower,
activeNode.matrixIndices!,
level,
currentSite,
gameProgress,
true
);
const nodeType = activeNode.type;
if (!nodeData) return;
if (activeNode.id === "" || !isNodeVisible(activeNode, gameProgress))
return;
if (nodeData.didMove) {
return {
event: keyPressToLower === "up" ? "site_up" : "site_down",
level: (keyPressToLower === "up" ? level + 1 : level - 1)
.toString()
.padStart(2, "0"),
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
};
} else {
return {
event: "change_node",
node: {
...getNodeById(nodeData.node, currentSite),
matrixIndices: nodeData.matrixIndices,
},
};
}
}
case "CIRCLE":
const eventAnimation =
Math.random() < 0.4 ? "rip_node" : "throw_node";
if (activeNode.upgrade_requirement > ssknLvl) {
const rejectAnimations = [
"touch_and_scare",
"knock_and_fall",
"knock",
];
const nodeType = activeNode.type;
const pickedAnim =
rejectAnimations[
Math.floor(Math.random() * rejectAnimations.length)
if (
activeNode.id === "" ||
!isNodeVisible(activeNode, gameProgress)
)
return;
if (activeNode.upgrade_requirement > ssknLvl) {
const rejectAnimations = [
"touch_and_scare",
"knock_and_fall",
"knock",
];
return {
event: pickedAnim,
siteRotY: siteRotY,
};
}
const pickedAnim =
rejectAnimations[
Math.floor(Math.random() * rejectAnimations.length)
];
switch (nodeType) {
case 0:
case 2:
case 4:
case 3:
case 5:
return {
event: `${eventAnimation}_media`,
scene: "media",
event: pickedAnim,
siteRotY: siteRotY,
level: level.toString().padStart(2, "0"),
};
case 6:
if (activeNode.node_name.substr(0, 3) === "TaK") {
return {
event: `${eventAnimation}_tak`,
scene: "tak",
siteRotY: siteRotY,
node: activeNode,
};
} else {
}
switch (nodeType) {
case 0:
case 2:
case 4:
case 3:
case 5:
return {
event: `${eventAnimation}_media`,
scene: "media",
siteRotY: siteRotY,
level: level.toString().padStart(2, "0"),
};
}
case 8:
return {
event: `${eventAnimation}_gate`,
scene: "gate",
siteRotY: siteRotY,
node: activeNode,
};
case 7:
return {
event: `${eventAnimation}_sskn`,
scene: "sskn",
siteRotY: siteRotY,
};
case 9:
const bodyPart = (() => {
switch (parseInt(activeNode.node_name.slice(-1))) {
case 6:
return "head";
case 5:
return "rightArm";
case 4:
return "leftArm";
case 3:
return "rightLeg";
case 2:
return "leftLeg";
case 1:
return "body";
case 6:
if (activeNode.node_name.substr(0, 3) === "TaK") {
return {
event: `${eventAnimation}_tak`,
scene: "tak",
siteRotY: siteRotY,
node: activeNode,
};
} else {
return {
event: `${eventAnimation}_media`,
scene: "media",
siteRotY: siteRotY,
level: level.toString().padStart(2, "0"),
};
}
})();
case 8:
return {
event: `${eventAnimation}_gate`,
scene: "gate",
siteRotY: siteRotY,
node: activeNode,
};
case 7:
return {
event: `${eventAnimation}_sskn`,
scene: "sskn",
siteRotY: siteRotY,
};
case 9:
const bodyPart = (() => {
switch (parseInt(activeNode.node_name.slice(-1))) {
case 6:
return "head";
case 5:
return "rightArm";
case 4:
return "leftArm";
case 3:
return "rightLeg";
case 2:
return "leftLeg";
case 1:
return "body";
}
})();
return {
event: `${eventAnimation}_polytan`,
scene: "polytan",
siteRotY: siteRotY,
node: activeNode,
bodyPart: bodyPart,
};
}
break;
case "L2":
return { event: "toggle_level_selection", level: level };
case "TRIANGLE":
return { event: "pause_game" };
case "SPACE":
return { event: "play_with_hair", siteRotY: siteRotY };
}
break;
case "level_selection":
switch (keyPress) {
case "UP":
if (currentSite === "a") {
if (selectedLevel + 1 <= 22)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
} else if (currentSite === "b") {
if (selectedLevel + 1 <= 13)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
}
break;
case "DOWN":
if (selectedLevel - 1 >= 1)
return {
event: `${eventAnimation}_polytan`,
scene: "polytan",
siteRotY: siteRotY,
node: activeNode,
bodyPart: bodyPart,
event: `level_selection_down`,
selectedLevelIdx: selectedLevel - 1,
};
}
break;
case "L2":
return { event: "toggle_level_selection", level: level };
case "TRIANGLE":
return { event: "pause_game" };
case "SPACE":
return { event: "play_with_hair", siteRotY: siteRotY };
}
break;
case "level_selection":
switch (keyPress) {
case "UP":
if (currentSite === "a") {
if (selectedLevel + 1 <= 22)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
} else if (currentSite === "b") {
if (selectedLevel + 1 <= 13)
return {
event: `level_selection_up`,
selectedLevelIdx: selectedLevel + 1,
};
}
break;
case "DOWN":
if (selectedLevel - 1 >= 1)
break;
case "X":
return {
event: `level_selection_down`,
selectedLevelIdx: selectedLevel - 1,
event: "level_selection_back",
};
break;
case "X":
case "CIRCLE":
if (level === selectedLevel) return;
const direction = selectedLevel > level ? "up" : "down";
const rowIdx = direction === "up" ? 2 : 0;
const nodeData = findNode(
activeNode.id,
direction,
{ ...activeNode.matrixIndices!, rowIdx: rowIdx },
selectedLevel,
currentSite,
gameProgress,
false
);
if (nodeData) {
const event =
selectedLevel < level ? "select_level_down" : "select_level_up";
return {
event: event,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
level: selectedLevel.toString().padStart(2, "0"),
};
}
}
break;
case "pause":
if (showingAbout)
return {
event: "level_selection_back",
event: "exit_about",
};
case "CIRCLE":
if (level === selectedLevel) return;
const direction = selectedLevel > level ? "up" : "down";
const rowIdx = direction === "up" ? 2 : 0;
const nodeData = findNode(
activeNode.id,
direction,
{ ...activeNode.matrixIndices!, rowIdx: rowIdx },
selectedLevel,
currentSite,
gameProgress,
false
);
if (nodeData) {
const event =
selectedLevel < level ? "select_level_down" : "select_level_up";
return {
event: event,
node: {
...(nodeData.node !== "unknown"
? getNodeById(nodeData.node, currentSite)
: unknownNodeTemplate),
matrixIndices: nodeData.matrixIndices,
},
level: selectedLevel.toString().padStart(2, "0"),
};
else {
switch (keyPress) {
case "UP":
if (pauseMatrixIdx - 1 < 0) break;
return {
event: "pause_up",
pauseMatrixIdx: pauseMatrixIdx - 1,
};
case "DOWN":
if (pauseMatrixIdx + 1 > 4) break;
return {
event: "pause_down",
pauseMatrixIdx: pauseMatrixIdx + 1,
};
case "CIRCLE":
if (activePauseComponent === "change") {
return {
event: "display_prompt",
};
}
}
}
break;
case "pause":
switch (keyPress) {
case "UP":
if (pauseMatrixIdx - 1 < 0) break;
return {
event: "pause_up",
pauseMatrixIdx: pauseMatrixIdx - 1,
};
case "DOWN":
if (pauseMatrixIdx + 1 > 4) break;
return {
event: "pause_down",
pauseMatrixIdx: pauseMatrixIdx + 1,
};
case "CIRCLE":
return {
event: `pause_${activePauseComponent}_select`,
site: currentSite,
};
}
}
break;
case "not_found":
return { event: "exit_not_found" };
}
}
};

View file

@ -8,6 +8,7 @@ const handleMediaKeyPress = (mediaSceneContext: any) => {
rightSideComponentIdx,
activeNode,
activeSite,
gameProgress,
} = mediaSceneContext;
const calculateNewRightSide = (
@ -72,14 +73,14 @@ const handleMediaKeyPress = (mediaSceneContext: any) => {
const data = findNodeFromWord(
activeMediaComponent,
activeNode,
activeSite
activeSite,
gameProgress
);
if (data) {
return { event: `media_${activeMediaComponent}_select`, ...data };
} else {
// todo in case node isnt unlocked yet
return;
return { event: `word_node_not_found` };
}
default:
if (activeMediaComponent === "play") {

View file

@ -5,9 +5,15 @@ const mainSubsceneManager = (eventState: any) => {
const dispatchAction = (eventState: { event: string }) => {
switch (eventState.event) {
case "word_node_not_found":
return {
action: () => setMainSubscene("not_found"),
delay: 0,
};
case "level_selection_back":
case "select_level_up":
case "select_level_down":
case "exit_not_found":
return {
action: () => setMainSubscene("site"),
delay: 0,

View file

@ -5,6 +5,7 @@ type PauseManagerProps = { event: string; pauseMatrixIdx: number };
const pauseManager = (eventState: any) => {
const setComponentMatrixIdx = useStore.getState().setPauseComponentMatrixIdx;
const setExitAnimation = useStore.getState().setPauseExitAnimation;
const setShowingAbout = useStore.getState().setShowingAbout;
const dispatchAction = (eventState: PauseManagerProps) => {
switch (eventState.event) {
@ -17,6 +18,14 @@ const pauseManager = (eventState: any) => {
return {
action: () => setExitAnimation(true),
};
case "pause_about_select":
return {
action: () => setShowingAbout(true),
};
case "exit_about":
return {
action: () => setShowingAbout(false),
};
case "pause_game":
return { action: () => setExitAnimation(false) };
}

View file

@ -1,5 +1,4 @@
import { useStore } from "../../../store";
import { useCallback } from "react";
import * as THREE from "three";
const mediaManager = (eventState: any) => {

View file

@ -0,0 +1,32 @@
import { useStore } from "../../store";
const promptManager = (eventState: any) => {
const setComponentMatrixIdx = useStore.getState().setPromptComponentMatrixIdx;
const setPromptVisible = useStore.getState().setPromptVisible;
const dispatchAction = (eventState: { event: string; scene: string }) => {
switch (eventState.event) {
case "display_prompt": {
return { action: () => setPromptVisible(true) };
}
case "prompt_right":
return {
action: () => setComponentMatrixIdx(1),
};
case "prompt_left":
return { action: () => setComponentMatrixIdx(0) };
case "pause_change_select":
return { action: () => setPromptVisible(false) };
case "exit_prompt":
return { action: () => setPromptVisible(false) };
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) {
action();
}
};
export default promptManager;

View file

@ -52,6 +52,7 @@ const sceneManager = (eventState: any) => {
case "media_fstWord_select":
case "media_sndWord_select":
case "media_thirdWord_select":
case "word_node_not_found":
return {
action: () =>
useStore.setState({ currentScene: "main", intro: false }),

View file

@ -13,6 +13,7 @@ import Site from "../components/MainScene/Site";
import Lain from "../components/MainScene/Lain";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import NotFound from "../components/MainScene/NotFound";
const MainScene = () => {
const intro = useStore((state) => state.intro);
@ -94,10 +95,13 @@ const MainScene = () => {
<Suspense fallback={null}>
<LevelSelection />
<Pause />
<NotFound visible={subscene === "not_found"} />
<group visible={!paused}>
<group visible={!wordSelected && (intro ? introFinished : true)}>
<HUD />
<YellowTextRenderer />
<group visible={subscene !== "not_found"}>
<HUD />
<YellowTextRenderer />
</group>
<MiddleRing />
<GrayPlanes />
</group>

View file

@ -44,6 +44,7 @@ type State = {
pauseComponentMatrix: ["load", "about", "change", "save", "exit"];
pauseComponentMatrixIdx: number;
pauseExitAnimation: boolean;
showingAbout: boolean;
// media/media scene
audioAnalyser: undefined | THREE.AudioAnalyser;
@ -98,6 +99,11 @@ type State = {
// end scene
endMediaPlayedCount: number;
// prompt
promptVisible: boolean;
promptComponentMatrix: ["yes", "no"];
promptComponentMatrixIdx: 1 | 0;
// save state
siteSaveState: {
a: {
@ -188,6 +194,7 @@ export const useStore = create(
pauseComponentMatrix: ["load", "about", "change", "save", "exit"],
pauseComponentMatrixIdx: 2,
pauseExitAnimation: false,
showingAbout: false,
// media / media scene
audioAnalyser: undefined,
@ -249,6 +256,11 @@ export const useStore = create(
// end scene
endMediaPlayedCount: 0,
// prompt
promptVisible: false,
promptComponentMatrix: ["yes", "no"],
promptComponentMatrixIdx: 1,
// save states for loading the game/changing sites
siteSaveState: {
a: {
@ -325,6 +337,7 @@ export const useStore = create(
set(() => ({ pauseComponentMatrixIdx: to })),
setPauseExitAnimation: (to: boolean) =>
set(() => ({ pauseExitAnimation: to })),
setShowingAbout: (to: boolean) => set(() => ({ showingAbout: to })),
// media/media scene setters
toggleMediaSide: () =>
@ -404,6 +417,11 @@ export const useStore = create(
})),
resetEndMediaPlayedCount: () => set(() => ({ endMediaPlayedCount: 0 })),
// prompt setters
setPromptVisible: (to: boolean) => set(() => ({ promptVisible: to })),
setPromptComponentMatrixIdx: (to: 1 | 0) =>
set(() => ({ promptComponentMatrixIdx: to })),
// site state setters
setSiteSaveState: (
site: string,
@ -467,6 +485,10 @@ export const getMainSceneContext = () => {
activeNode: state.activeNode,
level: parseInt(state.activeLevel),
ssknLvl: state.ssknLvl,
showingAbout: state.showingAbout,
promptVisible: state.promptVisible,
activePromptComponent:
state.promptComponentMatrix[state.promptComponentMatrixIdx],
};
};
@ -493,5 +515,6 @@ export const getMediaSceneContext = () => {
wordPosStateIdx: state.mediaWordPosStateIdx,
activeNode: state.activeNode,
activeSite: state.activeSite,
gameProgress: state.gameProgress,
};
};

View file

@ -1,15 +1,14 @@
import site_a from "../resources/site_a.json";
import site_b from "../resources/site_b.json";
import node_matrices from "../resources/node_matrices.json";
import {
NodeDataType,
SiteType,
} from "../components/MainScene/Site";
import { NodeDataType, SiteType } from "../components/MainScene/Site";
import { isNodeVisible } from "./node-utils";
export const findNodeFromWord = (
wordLabel: string,
activeNode: NodeDataType,
site: "a" | "b"
site: "a" | "b",
gameProgress: any
) => {
const labelToIdx = (() => {
switch (wordLabel) {
@ -41,7 +40,8 @@ export const findNodeFromWord = (
) + 1
] ?? nodesWithSameWords[0];
//todo check if visible
if (!isNodeVisible(chosenNode, gameProgress)) return;
const pos = chosenNode.id.substr(2);
const matrixIndices = Object.entries(node_matrices).flatMap((matrixData) =>