refactoring media scene state management

This commit is contained in:
ad044 2020-10-21 20:17:22 +04:00
parent 04bb8972d4
commit f166536e2f
11 changed files with 159 additions and 200 deletions

View file

@ -2,8 +2,8 @@ import React from "react";
import TriangularPrism from "./TriangularPrism"; import TriangularPrism from "./TriangularPrism";
import Cube from "./Cube"; import Cube from "./Cube";
type LeftSideShapesProps = { type LeftSideProps = {
active: "cube" | "triangle" | ""; activeMediaElement: string;
}; };
export type ShapeProps = { export type ShapeProps = {
@ -12,9 +12,9 @@ export type ShapeProps = {
active?: boolean; active?: boolean;
}; };
const LeftSide = (props: LeftSideShapesProps) => { const LeftSide = (props: LeftSideProps) => {
const cubesActive = props.active === "cube"; const cubesActive = props.activeMediaElement === "exit";
const trianglesActive = props.active === "triangle"; const trianglesActive = props.activeMediaElement === "play";
return ( return (
<> <>

View file

@ -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 grayTextureFile from "../../static/sprite/gray_box.png";
import darkGrayTextureFile from "../../static/sprite/dark_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 { useMediaStore, useMediaWordStore } from "../../store";
import TextRenderer from "../TextRenderer/TextRenderer"; import TextRenderer from "../TextRenderer/TextRenderer";
import LeftSide from "./LeftSide/LeftSide"; import LeftSide from "./LeftSide/LeftSide";
import Word from "./Word"; import Word from "./RightSide/Word";
import RightSide from "./RightSide/RightSide";
const MediaScene = () => { const MediaScene = () => {
const [grayCubesActive, setGrayCubesActive] = useState(false); const [grayCubesActive, setGrayCubesActive] = useState(false);
const mediaHudOverlayTex = useLoader(THREE.TextureLoader, mediaOverlayHud); const mediaHudOverlayTex = useLoader(THREE.TextureLoader, mediaOverlayHud);
const words = useMediaWordStore((state) => state.words);
const activeMediaElement = useMediaStore((state) => state.activeMediaElement); const activeMediaElement = useMediaStore((state) => state.activeMediaElement);
@ -31,10 +31,8 @@ const MediaScene = () => {
</group> </group>
<pointLight intensity={1.2} color={0xffffff} position={[-2, 0, 3]} /> <pointLight intensity={1.2} color={0xffffff} position={[-2, 0, 3]} />
<LeftSide active={"cube"} /> <LeftSide activeMediaElement={activeMediaElement} />
<Word word={words[0]} posX={1} posY={1} /> <RightSide activeMediaElement={activeMediaElement} />
<Word word={words[1]} posX={0} posY={0} />
<Word word={words[2]} posX={-1} posY={-1} />
</group> </group>
</> </>
); );

View 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;

View file

@ -1,13 +1,15 @@
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import * as THREE from "three"; import * as THREE from "three";
import wordInactiveTexture from "../../static/sprite/word_background.png"; import wordInactiveTexture from "../../../static/sprite/word_background.png";
import wordActiveTexture from "../../static/sprite/word_background_active.png"; import wordActiveTexture from "../../../static/sprite/word_background_active.png";
import { useLoader } from "react-three-fiber"; import { useLoader } from "react-three-fiber";
import { a, SpringValue } from "@react-spring/three";
type WordProps = { type WordProps = {
word: string; word: string;
posX: number; posX: SpringValue<number>;
posY: number; posY: SpringValue<number>;
active: boolean;
}; };
const Word = (props: WordProps) => { const Word = (props: WordProps) => {
@ -24,13 +26,13 @@ const Word = (props: WordProps) => {
const wordActiveTex = useLoader(THREE.TextureLoader, wordActiveTexture); const wordActiveTex = useLoader(THREE.TextureLoader, wordActiveTexture);
return ( 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}> <mesh scale={[0.4, 0.4, 0]} position={[-3.9, 1.915, 0]} renderOrder={3}>
<planeBufferGeometry attach="geometry" /> <planeBufferGeometry attach="geometry" />
<textGeometry attach="geometry" args={[props.word, config]} /> <textGeometry attach="geometry" args={[props.word, config]} />
<meshBasicMaterial <meshBasicMaterial
attach="material" attach="material"
color={0x000000} color={props.active ? 0xffffff : 0x000000}
transparent={true} transparent={true}
/> />
</mesh> </mesh>
@ -38,11 +40,11 @@ const Word = (props: WordProps) => {
<sprite scale={[4.2, 0.45, 1]} position={[-2, 2, 0]} renderOrder={2}> <sprite scale={[4.2, 0.45, 1]} position={[-2, 2, 0]} renderOrder={2}>
<spriteMaterial <spriteMaterial
attach="material" attach="material"
map={wordInactiveTex} map={props.active ? wordActiveTex : wordInactiveTex}
alphaTest={0.01} alphaTest={0.01}
/> />
</sprite> </sprite>
</group> </a.group>
); );
}; };

View file

@ -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;

View file

@ -6,9 +6,8 @@ import BlueOrbStateManager from "./BlueOrbStateManager";
import BlueOrbHUDStateManager from "./BlueOrbHUDStateManager"; import BlueOrbHUDStateManager from "./BlueOrbHUDStateManager";
import YellowTextStateManager from "./YellowTextStateManager"; import YellowTextStateManager from "./YellowTextStateManager";
import { useBlueOrbStore, useMediaStore } from "../../store"; import { useBlueOrbStore, useMediaStore } from "../../store";
import MediaSceneStateManager from "./MediaSceneStateManager";
import GreenTextStateManager from "./GreenTextStateManager"; import GreenTextStateManager from "./GreenTextStateManager";
import ActiveMediaElementStateManager from "./ActiveMediaElementStateManager"; import ActiveMediaElementStateManager from "./MediaScene/ActiveMediaElementStateManager";
const getKeyCodeAssociation = (keyCode: number): string => { const getKeyCodeAssociation = (keyCode: number): string => {
const keyCodeAssocs = { const keyCodeAssocs = {
@ -56,6 +55,7 @@ const EventStateManager = () => {
// const eventId = `${activeBlueOrb}_${keyPress}`; // const eventId = `${activeBlueOrb}_${keyPress}`;
// //
const eventId = `${activeMediaElement}_${keyPress}`; const eventId = `${activeMediaElement}_${keyPress}`;
console.log(activeMediaElement)
setEventState(eventId); setEventState(eventId);
} }
}, },

View file

@ -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;

View file

@ -3,7 +3,7 @@ import blue_orb_huds from "../../resources/blue_orb_huds.json";
import site_a from "../../resources/site_a.json"; import site_a from "../../resources/site_a.json";
import { useTextRendererStore } from "../../store"; import { useTextRendererStore } from "../../store";
import blue_orb_directions from "../../resources/blue_orb_directions.json"; 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"; import { EventObject } from "./EventStateManager";
type AnimateYellowTextWithMove = ( type AnimateYellowTextWithMove = (
@ -168,11 +168,10 @@ const YellowTextStateManager = (props: any) => {
( (
event: string, event: string,
targetBlueOrbHudId: string | undefined, targetBlueOrbHudId: string | undefined,
targetBlueOrbId: string | undefined, targetBlueOrbId: string | undefined
targetMediaElementText: string | undefined,
targetMediaElementTextPos: number[] | undefined
) => { ) => {
const dispatcherObjects: YellowTextDispatcher = { const dispatcherObjects: YellowTextDispatcher = {
// main scene
moveUp: { moveUp: {
action: animateYellowTextWithMove, action: animateYellowTextWithMove,
value: [-1.5, targetBlueOrbHudId, targetBlueOrbId], value: [-1.5, targetBlueOrbHudId, targetBlueOrbId],
@ -193,13 +192,14 @@ const YellowTextStateManager = (props: any) => {
action: animateYellowTextWithoutMove, action: animateYellowTextWithoutMove,
value: [targetBlueOrbHudId, targetBlueOrbId], value: [targetBlueOrbHudId, targetBlueOrbId],
}, },
// media scene
setActivePlay: { setActivePlay: {
action: animateMediaYellowText, action: animateMediaYellowText,
value: [targetMediaElementText, targetMediaElementTextPos], value: ["Play", [-0.8, 0.05, 0.6]],
}, },
setActiveExit: { setActiveExit: {
action: animateMediaYellowText, 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 targetBlueOrbId = eventObject.target_blue_orb_id;
const targetBlueOrbHudId = eventObject.target_hud_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( const dispatchedObject = dispatchObject(
eventAction, eventAction,
targetBlueOrbHudId, targetBlueOrbHudId,
targetBlueOrbId, targetBlueOrbId
targetMediaElementText,
targetMediaElementTextPos
); );
if (dispatchedObject) { if (dispatchedObject) {

View 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
}
}

View file

@ -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]
}
}

View file

@ -85,15 +85,25 @@ type MiddleRingState = {
setMiddleRingAnimDuration: (to: number) => void; 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 = { type MediaWordState = {
wordStateDataStruct: MediaWordData[];
wordStateDataStructIdx: number;
words: string[]; words: string[];
fstWordPos: number[]; activeWordIdx: number;
sndWordPos: number[]; lastActiveWordIdx: number;
thirdWordPos: number[];
setWords: (to: string[]) => void; setWords: (to: string[]) => void;
setFstWordPos: (to: number[]) => void; addToActiveWordIdx: (val: number) => void;
setSndWordPos: (to: number[]) => void; addToWordStateDataStructIdx: (val: number) => void;
setThirdWordPos: (to: number[]) => void; setLastActiveWordIdx: (to: number) => void;
}; };
type MediaState = { type MediaState = {
@ -257,12 +267,36 @@ export const useMediaStore = create<MediaState>((set) => ({
})); }));
export const useMediaWordStore = create<MediaWordState>((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"], words: ["eye", "quiet", "hallucination"],
fstWordPos: [0, 0, 0], activeWordIdx: 0,
sndWordPos: [0, 0, 0], lastActiveWordIdx: 0,
thirdWordPos: [0, 0, 0],
setWords: (to) => set(() => ({ words: to })), setWords: (to) => set(() => ({ words: to })),
setFstWordPos: (to) => set(() => ({ fstWordPos: to })), setLastActiveWordIdx: (to) => set(() => ({ lastActiveWordIdx: to })),
setSndWordPos: (to) => set(() => ({ sndWordPos: to })), addToWordStateDataStructIdx: (val) =>
setThirdWordPos: (to) => set(() => ({ thirdWordPos: to })), set((state) => ({
wordStateDataStructIdx: state.wordStateDataStructIdx + val,
})),
addToActiveWordIdx: (val) =>
set((state) => ({
activeWordIdx: state.activeWordIdx + val,
})),
})); }));