mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
refactoring media scene state management
This commit is contained in:
parent
04bb8972d4
commit
f166536e2f
11 changed files with 159 additions and 200 deletions
|
@ -2,8 +2,8 @@ import React from "react";
|
|||
import TriangularPrism from "./TriangularPrism";
|
||||
import Cube from "./Cube";
|
||||
|
||||
type LeftSideShapesProps = {
|
||||
active: "cube" | "triangle" | "";
|
||||
type LeftSideProps = {
|
||||
activeMediaElement: string;
|
||||
};
|
||||
|
||||
export type ShapeProps = {
|
||||
|
@ -12,9 +12,9 @@ export type ShapeProps = {
|
|||
active?: boolean;
|
||||
};
|
||||
|
||||
const LeftSide = (props: LeftSideShapesProps) => {
|
||||
const cubesActive = props.active === "cube";
|
||||
const trianglesActive = props.active === "triangle";
|
||||
const LeftSide = (props: LeftSideProps) => {
|
||||
const cubesActive = props.activeMediaElement === "exit";
|
||||
const trianglesActive = props.activeMediaElement === "play";
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import React, { useCallback, useRef, useState } from "react";
|
||||
|
||||
import grayTextureFile from "../../static/sprite/gray_box.png";
|
||||
import darkGrayTextureFile from "../../static/sprite/dark_gray_box.png";
|
||||
|
@ -10,12 +10,12 @@ import { OrbitControls } from "drei";
|
|||
import { useMediaStore, useMediaWordStore } from "../../store";
|
||||
import TextRenderer from "../TextRenderer/TextRenderer";
|
||||
import LeftSide from "./LeftSide/LeftSide";
|
||||
import Word from "./Word";
|
||||
import Word from "./RightSide/Word";
|
||||
import RightSide from "./RightSide/RightSide";
|
||||
|
||||
const MediaScene = () => {
|
||||
const [grayCubesActive, setGrayCubesActive] = useState(false);
|
||||
const mediaHudOverlayTex = useLoader(THREE.TextureLoader, mediaOverlayHud);
|
||||
const words = useMediaWordStore((state) => state.words);
|
||||
|
||||
const activeMediaElement = useMediaStore((state) => state.activeMediaElement);
|
||||
|
||||
|
@ -31,10 +31,8 @@ const MediaScene = () => {
|
|||
</group>
|
||||
|
||||
<pointLight intensity={1.2} color={0xffffff} position={[-2, 0, 3]} />
|
||||
<LeftSide active={"cube"} />
|
||||
<Word word={words[0]} posX={1} posY={1} />
|
||||
<Word word={words[1]} posX={0} posY={0} />
|
||||
<Word word={words[2]} posX={-1} posY={-1} />
|
||||
<LeftSide activeMediaElement={activeMediaElement} />
|
||||
<RightSide activeMediaElement={activeMediaElement} />
|
||||
</group>
|
||||
</>
|
||||
);
|
||||
|
|
58
src/components/MediaScene/RightSide/RightSide.tsx
Normal file
58
src/components/MediaScene/RightSide/RightSide.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import React, { useCallback } from "react";
|
||||
import { useMediaWordStore } from "../../../store";
|
||||
import Word from "./Word";
|
||||
import { useSpring } from "@react-spring/three";
|
||||
|
||||
type RightSideProps = {
|
||||
activeMediaElement: string;
|
||||
};
|
||||
|
||||
const RightSide = (props: RightSideProps) => {
|
||||
const words = useMediaWordStore((state) => state.words);
|
||||
|
||||
const wordStateDataStructIdx = useMediaWordStore(
|
||||
(state) => state.wordStateDataStructIdx
|
||||
);
|
||||
|
||||
const wordState = useMediaWordStore(
|
||||
useCallback((state) => state.wordStateDataStruct[wordStateDataStructIdx], [
|
||||
wordStateDataStructIdx,
|
||||
])
|
||||
);
|
||||
|
||||
console.log(wordStateDataStructIdx);
|
||||
const wordStateSpring = useSpring({
|
||||
fstWordPosX: wordState.positions.fstWord.posX,
|
||||
fstWordPosY: wordState.positions.fstWord.posY,
|
||||
sndWordPosX: wordState.positions.sndWord.posX,
|
||||
sndWordPosY: wordState.positions.sndWord.posY,
|
||||
thirdWordPosX: wordState.positions.thirdWord.posX,
|
||||
thirdWordPosY: wordState.positions.thirdWord.posY,
|
||||
config: { duration: 300 },
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Word
|
||||
word={words[0]}
|
||||
posX={wordStateSpring.fstWordPosX}
|
||||
posY={wordStateSpring.fstWordPosY}
|
||||
active={props.activeMediaElement === "fstWord"}
|
||||
/>
|
||||
<Word
|
||||
word={words[1]}
|
||||
posX={wordStateSpring.sndWordPosX}
|
||||
posY={wordStateSpring.sndWordPosY}
|
||||
active={props.activeMediaElement === "sndWord"}
|
||||
/>
|
||||
<Word
|
||||
word={words[2]}
|
||||
posX={wordStateSpring.thirdWordPosX}
|
||||
posY={wordStateSpring.thirdWordPosY}
|
||||
active={props.activeMediaElement === "thirdWord"}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RightSide;
|
|
@ -1,13 +1,15 @@
|
|||
import React, { useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
import wordInactiveTexture from "../../static/sprite/word_background.png";
|
||||
import wordActiveTexture from "../../static/sprite/word_background_active.png";
|
||||
import wordInactiveTexture from "../../../static/sprite/word_background.png";
|
||||
import wordActiveTexture from "../../../static/sprite/word_background_active.png";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
import { a, SpringValue } from "@react-spring/three";
|
||||
|
||||
type WordProps = {
|
||||
word: string;
|
||||
posX: number;
|
||||
posY: number;
|
||||
posX: SpringValue<number>;
|
||||
posY: SpringValue<number>;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
const Word = (props: WordProps) => {
|
||||
|
@ -24,13 +26,13 @@ const Word = (props: WordProps) => {
|
|||
const wordActiveTex = useLoader(THREE.TextureLoader, wordActiveTexture);
|
||||
|
||||
return (
|
||||
<group position-x={props.posX} position-y={props.posY}>
|
||||
<a.group position-x={props.posX} position-y={props.posY}>
|
||||
<mesh scale={[0.4, 0.4, 0]} position={[-3.9, 1.915, 0]} renderOrder={3}>
|
||||
<planeBufferGeometry attach="geometry" />
|
||||
<textGeometry attach="geometry" args={[props.word, config]} />
|
||||
<meshBasicMaterial
|
||||
attach="material"
|
||||
color={0x000000}
|
||||
color={props.active ? 0xffffff : 0x000000}
|
||||
transparent={true}
|
||||
/>
|
||||
</mesh>
|
||||
|
@ -38,11 +40,11 @@ const Word = (props: WordProps) => {
|
|||
<sprite scale={[4.2, 0.45, 1]} position={[-2, 2, 0]} renderOrder={2}>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={wordInactiveTex}
|
||||
map={props.active ? wordActiveTex : wordInactiveTex}
|
||||
alphaTest={0.01}
|
||||
/>
|
||||
</sprite>
|
||||
</group>
|
||||
</a.group>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
import React, { useCallback, useEffect } from "react";
|
||||
import { useMediaStore } from "../../store";
|
||||
import { StateManagerProps } from "./EventStateManager";
|
||||
import media_scene_directions from "../../resources/media_scene_directions.json";
|
||||
|
||||
const ActiveMediaElementStateManager = (props: StateManagerProps) => {
|
||||
const setActiveMediaElement = useMediaStore(
|
||||
(state) => state.setActiveMediaElement
|
||||
);
|
||||
|
||||
const dispatchObject = useCallback(
|
||||
(event: string, targetMediaElement: string) => {
|
||||
const dispatcherObjects = {
|
||||
setActivePlay: {
|
||||
action: setActiveMediaElement,
|
||||
value: targetMediaElement,
|
||||
},
|
||||
setActiveExit: {
|
||||
action: setActiveMediaElement,
|
||||
value: targetMediaElement,
|
||||
},
|
||||
};
|
||||
|
||||
return dispatcherObjects[event as keyof typeof dispatcherObjects];
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.eventState) {
|
||||
const eventObject =
|
||||
media_scene_directions[
|
||||
props.eventState as keyof typeof media_scene_directions
|
||||
];
|
||||
|
||||
if (eventObject) {
|
||||
const eventAction = eventObject.action;
|
||||
|
||||
const targetMediaElement = eventObject.target_media_element;
|
||||
|
||||
const dispatchedObject = dispatchObject(
|
||||
eventAction,
|
||||
targetMediaElement
|
||||
);
|
||||
|
||||
if (dispatchedObject) {
|
||||
dispatchedObject.action(dispatchedObject.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [props.eventState, dispatchObject]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default ActiveMediaElementStateManager;
|
|
@ -6,9 +6,8 @@ import BlueOrbStateManager from "./BlueOrbStateManager";
|
|||
import BlueOrbHUDStateManager from "./BlueOrbHUDStateManager";
|
||||
import YellowTextStateManager from "./YellowTextStateManager";
|
||||
import { useBlueOrbStore, useMediaStore } from "../../store";
|
||||
import MediaSceneStateManager from "./MediaSceneStateManager";
|
||||
import GreenTextStateManager from "./GreenTextStateManager";
|
||||
import ActiveMediaElementStateManager from "./ActiveMediaElementStateManager";
|
||||
import ActiveMediaElementStateManager from "./MediaScene/ActiveMediaElementStateManager";
|
||||
|
||||
const getKeyCodeAssociation = (keyCode: number): string => {
|
||||
const keyCodeAssocs = {
|
||||
|
@ -56,6 +55,7 @@ const EventStateManager = () => {
|
|||
// const eventId = `${activeBlueOrb}_${keyPress}`;
|
||||
//
|
||||
const eventId = `${activeMediaElement}_${keyPress}`;
|
||||
console.log(activeMediaElement)
|
||||
setEventState(eventId);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
import React, { useCallback, useEffect } from "react";
|
||||
import { useMediaStore } from "../../store";
|
||||
import media_scene_directions from "../../resources/media_scene_directions.json";
|
||||
import { StateManagerProps } from "./EventStateManager";
|
||||
|
||||
const MediaSceneStateManager = (props: StateManagerProps) => {
|
||||
const setActiveMediaElement = useMediaStore(
|
||||
(state) => state.setActiveMediaElement
|
||||
);
|
||||
const setActiveMediaElementText = useMediaStore(
|
||||
(state) => state.setLeftColActiveMediaElementText
|
||||
);
|
||||
const setActiveMediaElementTextPos = useMediaStore(
|
||||
(state) => state.setLeftColActiveMediaElementTextPos
|
||||
);
|
||||
|
||||
const updateActiveMediaElementAnimate = useCallback(
|
||||
(
|
||||
targetMediaElement: string,
|
||||
targetMediaElementText,
|
||||
targetMediaElementTextPos
|
||||
) => {
|
||||
setActiveMediaElement(targetMediaElement);
|
||||
setActiveMediaElementText(targetMediaElementText);
|
||||
setActiveMediaElementTextPos(targetMediaElementTextPos);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const dispatchObject = useCallback(
|
||||
(
|
||||
event: string,
|
||||
targetMediaElement: string,
|
||||
targetMediaElementText,
|
||||
targetMediaElementTextPos
|
||||
) => {
|
||||
const dispatcherObjects = {
|
||||
setActiveMediaElement: {
|
||||
action: updateActiveMediaElementAnimate,
|
||||
value: [
|
||||
targetMediaElement,
|
||||
targetMediaElementText,
|
||||
targetMediaElementTextPos,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
return dispatcherObjects[event as keyof typeof dispatcherObjects];
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.eventState) {
|
||||
const eventObject =
|
||||
media_scene_directions[
|
||||
props.eventState as keyof typeof media_scene_directions
|
||||
];
|
||||
if (eventObject) {
|
||||
const eventAction = eventObject.action;
|
||||
const targetMediaElement = eventObject.target_media_element;
|
||||
const targetMediaElementText = eventObject.target_media_element_text;
|
||||
const targetMediaElementTextPos =
|
||||
eventObject.target_media_element_text_position;
|
||||
|
||||
const dispatchedObject = dispatchObject(
|
||||
eventAction,
|
||||
targetMediaElement,
|
||||
targetMediaElementText,
|
||||
targetMediaElementTextPos
|
||||
);
|
||||
if (dispatchedObject) {
|
||||
(dispatchedObject.action as any).apply(null, dispatchedObject.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [props.eventState, dispatchObject]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default MediaSceneStateManager;
|
|
@ -3,7 +3,7 @@ import blue_orb_huds from "../../resources/blue_orb_huds.json";
|
|||
import site_a from "../../resources/site_a.json";
|
||||
import { useTextRendererStore } from "../../store";
|
||||
import blue_orb_directions from "../../resources/blue_orb_directions.json";
|
||||
import media_scene_directions from "../../resources/media_scene_directions.json";
|
||||
import media_scene_directions from "../../resources/media_scene_actions.json";
|
||||
import { EventObject } from "./EventStateManager";
|
||||
|
||||
type AnimateYellowTextWithMove = (
|
||||
|
@ -168,11 +168,10 @@ const YellowTextStateManager = (props: any) => {
|
|||
(
|
||||
event: string,
|
||||
targetBlueOrbHudId: string | undefined,
|
||||
targetBlueOrbId: string | undefined,
|
||||
targetMediaElementText: string | undefined,
|
||||
targetMediaElementTextPos: number[] | undefined
|
||||
targetBlueOrbId: string | undefined
|
||||
) => {
|
||||
const dispatcherObjects: YellowTextDispatcher = {
|
||||
// main scene
|
||||
moveUp: {
|
||||
action: animateYellowTextWithMove,
|
||||
value: [-1.5, targetBlueOrbHudId, targetBlueOrbId],
|
||||
|
@ -193,13 +192,14 @@ const YellowTextStateManager = (props: any) => {
|
|||
action: animateYellowTextWithoutMove,
|
||||
value: [targetBlueOrbHudId, targetBlueOrbId],
|
||||
},
|
||||
// media scene
|
||||
setActivePlay: {
|
||||
action: animateMediaYellowText,
|
||||
value: [targetMediaElementText, targetMediaElementTextPos],
|
||||
value: ["Play", [-0.8, 0.05, 0.6]],
|
||||
},
|
||||
setActiveExit: {
|
||||
action: animateMediaYellowText,
|
||||
value: [targetMediaElementText, targetMediaElementTextPos],
|
||||
value: ["Exit", [-0.8, -0.08, 0.6]],
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -229,17 +229,10 @@ const YellowTextStateManager = (props: any) => {
|
|||
const targetBlueOrbId = eventObject.target_blue_orb_id;
|
||||
const targetBlueOrbHudId = eventObject.target_hud_id;
|
||||
|
||||
// media scene specific
|
||||
const targetMediaElementText = eventObject.target_media_element_text;
|
||||
const targetMediaElementTextPos =
|
||||
eventObject.target_media_element_text_position;
|
||||
|
||||
const dispatchedObject = dispatchObject(
|
||||
eventAction,
|
||||
targetBlueOrbHudId,
|
||||
targetBlueOrbId,
|
||||
targetMediaElementText,
|
||||
targetMediaElementTextPos
|
||||
targetBlueOrbId
|
||||
);
|
||||
|
||||
if (dispatchedObject) {
|
||||
|
|
26
src/resources/media_scene_actions.json
Normal file
26
src/resources/media_scene_actions.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"play_down": {
|
||||
"action": "setActiveMediaElement",
|
||||
"value": "exit"
|
||||
},
|
||||
"exit_up": {
|
||||
"action": "setActiveMediaElement",
|
||||
"value": "play"
|
||||
},
|
||||
"exit_right": {
|
||||
"action": "setActiveWords",
|
||||
"value": "lastActiveWord"
|
||||
},
|
||||
"play_right": {
|
||||
"action": "setActiveWords",
|
||||
"value": "lastActiveWord"
|
||||
},
|
||||
"fstWord_down": {
|
||||
"action": "addToWordState",
|
||||
"value": -1
|
||||
},
|
||||
"fstWord_up": {
|
||||
"action": "addToWordState",
|
||||
"value": 1
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"play_down": {
|
||||
"action": "setActivePlay",
|
||||
"target_media_element": "exit",
|
||||
"target_media_element_text": "Exit",
|
||||
"target_media_element_text_position": [-0.8, -0.08, 0.6]
|
||||
},
|
||||
"exit_up": {
|
||||
"action": "setActiveExit",
|
||||
"target_media_element": "play",
|
||||
"target_media_element_text": "Play",
|
||||
"target_media_element_text_position": [-0.8, 0.05, 0.6]
|
||||
}
|
||||
}
|
58
src/store.ts
58
src/store.ts
|
@ -85,15 +85,25 @@ type MiddleRingState = {
|
|||
setMiddleRingAnimDuration: (to: number) => void;
|
||||
};
|
||||
|
||||
type MediaWordData = {
|
||||
activeWord: string;
|
||||
positions: {
|
||||
fstWord: { posX: number; posY: number };
|
||||
sndWord: { posX: number; posY: number };
|
||||
thirdWord: { posX: number; posY: number };
|
||||
};
|
||||
};
|
||||
|
||||
type MediaWordState = {
|
||||
wordStateDataStruct: MediaWordData[];
|
||||
wordStateDataStructIdx: number;
|
||||
words: string[];
|
||||
fstWordPos: number[];
|
||||
sndWordPos: number[];
|
||||
thirdWordPos: number[];
|
||||
activeWordIdx: number;
|
||||
lastActiveWordIdx: number;
|
||||
setWords: (to: string[]) => void;
|
||||
setFstWordPos: (to: number[]) => void;
|
||||
setSndWordPos: (to: number[]) => void;
|
||||
setThirdWordPos: (to: number[]) => void;
|
||||
addToActiveWordIdx: (val: number) => void;
|
||||
addToWordStateDataStructIdx: (val: number) => void;
|
||||
setLastActiveWordIdx: (to: number) => void;
|
||||
};
|
||||
|
||||
type MediaState = {
|
||||
|
@ -257,12 +267,36 @@ export const useMediaStore = create<MediaState>((set) => ({
|
|||
}));
|
||||
|
||||
export const useMediaWordStore = create<MediaWordState>((set) => ({
|
||||
wordStateDataStruct: [
|
||||
{
|
||||
activeWord: "fstWord",
|
||||
positions: {
|
||||
fstWord: { posX: 0, posY: 0 },
|
||||
sndWord: { posX: 3, posY: -3 },
|
||||
thirdWord: { posX: 3.7, posY: -4.3 },
|
||||
},
|
||||
},
|
||||
{
|
||||
activeWord: "sndWord",
|
||||
positions: {
|
||||
fstWord: { posX: 1.8, posY: -2.5 },
|
||||
sndWord: { posX: 1.5, posY: -1.5 },
|
||||
thirdWord: { posX: 3.3, posY: -3.7 },
|
||||
},
|
||||
},
|
||||
],
|
||||
wordStateDataStructIdx: 0,
|
||||
words: ["eye", "quiet", "hallucination"],
|
||||
fstWordPos: [0, 0, 0],
|
||||
sndWordPos: [0, 0, 0],
|
||||
thirdWordPos: [0, 0, 0],
|
||||
activeWordIdx: 0,
|
||||
lastActiveWordIdx: 0,
|
||||
setWords: (to) => set(() => ({ words: to })),
|
||||
setFstWordPos: (to) => set(() => ({ fstWordPos: to })),
|
||||
setSndWordPos: (to) => set(() => ({ sndWordPos: to })),
|
||||
setThirdWordPos: (to) => set(() => ({ thirdWordPos: to })),
|
||||
setLastActiveWordIdx: (to) => set(() => ({ lastActiveWordIdx: to })),
|
||||
addToWordStateDataStructIdx: (val) =>
|
||||
set((state) => ({
|
||||
wordStateDataStructIdx: state.wordStateDataStructIdx + val,
|
||||
})),
|
||||
addToActiveWordIdx: (val) =>
|
||||
set((state) => ({
|
||||
activeWordIdx: state.activeWordIdx + val,
|
||||
})),
|
||||
}));
|
||||
|
|
Loading…
Reference in a new issue