fixed media scene text interaction, also added ability to dynamically display baseline offsets on fonts.

This commit is contained in:
ad044 2020-10-20 19:08:34 +04:00
parent bbbc929801
commit 813063953a
13 changed files with 12183 additions and 12046 deletions

View file

@ -26,10 +26,10 @@ const App = () => {
<span className="canvas"> <span className="canvas">
<EventStateManager /> <EventStateManager />
<Canvas concurrent> <Canvas concurrent>
{/*<Suspense fallback={null}>*/} <Suspense fallback={null}>
{/* <MediaOverlay />*/} <MediaOverlay />
{/*</Suspense>*/} </Suspense>
<MainScene /> {/*<MainScene />*/}
</Canvas> </Canvas>
</span> </span>
<MediaPlayer /> <MediaPlayer />

View file

@ -202,7 +202,10 @@ const MediaOverlay = () => {
<spriteMaterial attach="material" map={mediaHudOverlayTex} /> <spriteMaterial attach="material" map={mediaHudOverlayTex} />
</sprite> </sprite>
<group position={[0.4, -0.3, 0]}> <group position={[0.4, -0.3, 0]}>
<TextRenderer /> <group position={[0, 0, 13]} scale={[1, 1, 1]}>
<TextRenderer />
</group>
<pointLight intensity={1.2} color={0xffffff} position={[-2, 0, 3]} /> <pointLight intensity={1.2} color={0xffffff} position={[-2, 0, 3]} />
<GrayCube position={[-2.7, -1.6, 0.6]} active={grayCubesActive} /> <GrayCube position={[-2.7, -1.6, 0.6]} active={grayCubesActive} />

View file

@ -0,0 +1,56 @@
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

@ -8,6 +8,7 @@ import YellowTextStateManager from "./YellowTextStateManager";
import { useBlueOrbStore, useMediaStore } from "../../store"; import { useBlueOrbStore, useMediaStore } from "../../store";
import MediaSceneStateManager from "./MediaSceneStateManager"; import MediaSceneStateManager from "./MediaSceneStateManager";
import GreenTextStateManager from "./GreenTextStateManager"; import GreenTextStateManager from "./GreenTextStateManager";
import ActiveMediaElementStateManager from "./ActiveMediaElementStateManager";
const getKeyCodeAssociation = (keyCode: number): string => { const getKeyCodeAssociation = (keyCode: number): string => {
const keyCodeAssocs = { const keyCodeAssocs = {
@ -24,6 +25,16 @@ export type StateManagerProps = {
eventState: string; eventState: string;
}; };
export type EventObject = {
action: string;
target_blue_orb_id?: string;
target_hud_id?: string;
target_media_element?: string;
target_media_element_text?: string;
target_media_element_text_position?: number[];
};
const EventStateManager = () => { const EventStateManager = () => {
const [eventState, setEventState] = useState<string>(); const [eventState, setEventState] = useState<string>();
const activeBlueOrb = useBlueOrbStore((state) => state.blueOrbId); const activeBlueOrb = useBlueOrbStore((state) => state.blueOrbId);
@ -44,7 +55,7 @@ const EventStateManager = () => {
// from blue_orb_directions.json file. // from blue_orb_directions.json file.
// const eventId = `${activeBlueOrb}_${keyPress}`; // const eventId = `${activeBlueOrb}_${keyPress}`;
// //
const eventId = `${activeBlueOrb}_${keyPress}`; const eventId = `${activeMediaElement}_${keyPress}`;
setEventState(eventId); setEventState(eventId);
} }
}, },
@ -68,7 +79,7 @@ const EventStateManager = () => {
<SiteStateManager eventState={eventState!} /> <SiteStateManager eventState={eventState!} />
<LainStateManager eventState={eventState!} /> <LainStateManager eventState={eventState!} />
<MiddleRingStateManager eventState={eventState!} /> <MiddleRingStateManager eventState={eventState!} />
<MediaSceneStateManager eventState={eventState!} /> <ActiveMediaElementStateManager eventState={eventState!} />
</> </>
); );
}; };

View file

@ -22,7 +22,7 @@ const GreenTextStateManager = (props: StateManagerProps) => {
toggleGreenText(); toggleGreenText();
}, delay); }, delay);
}, },
[] [setGreenText, toggleGreenText]
); );
const dispatchObject = useCallback( const dispatchObject = useCallback(

View file

@ -3,6 +3,8 @@ 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 { EventObject } from "./EventStateManager";
type AnimateYellowTextWithMove = ( type AnimateYellowTextWithMove = (
yellowLetterPosYOffset: number, yellowLetterPosYOffset: number,
@ -15,8 +17,16 @@ type AnimateYellowTextWithoutMove = (
targetBlueOrbId: string targetBlueOrbId: string
) => void; ) => void;
type AnimateMediaYellowText = (
targetMediaText: string,
targetMediaTextPos: number[]
) => void;
type YellowTextDispatchData = { type YellowTextDispatchData = {
action: AnimateYellowTextWithMove | AnimateYellowTextWithoutMove; action:
| AnimateYellowTextWithMove
| AnimateYellowTextWithoutMove
| AnimateMediaYellowText;
value: any; value: any;
}; };
@ -26,6 +36,8 @@ type YellowTextDispatcher = {
moveLeft: YellowTextDispatchData; moveLeft: YellowTextDispatchData;
moveRight: YellowTextDispatchData; moveRight: YellowTextDispatchData;
changeBlueOrbFocus: YellowTextDispatchData; changeBlueOrbFocus: YellowTextDispatchData;
setActivePlay: YellowTextDispatchData;
setActiveExit: YellowTextDispatchData;
}; };
const YellowTextStateManager = (props: any) => { const YellowTextStateManager = (props: any) => {
@ -125,8 +137,41 @@ const YellowTextStateManager = (props: any) => {
] ]
); );
const animateMediaYellowText: AnimateMediaYellowText = useCallback(
(targetMediaElementText: string, targetMediaElementTextPos: number[]) => {
// make current text shrink
setYellowTextOffsetXCoeff(-1);
setTimeout(() => {
setYellowTextPosX(targetMediaElementTextPos[0]);
setYellowTextPosY(targetMediaElementTextPos[1]);
}, 400);
setTimeout(() => {
setYellowText(targetMediaElementText);
}, 1000);
setTimeout(() => {
// unshrink text
setYellowTextOffsetXCoeff(0);
}, 1200);
},
[
setYellowText,
setYellowTextOffsetXCoeff,
setYellowTextPosX,
setYellowTextPosY,
]
);
const dispatchObject = useCallback( const dispatchObject = useCallback(
(event: string, targetBlueOrbHudId: string, targetBlueOrbId: string) => { (
event: string,
targetBlueOrbHudId: string | undefined,
targetBlueOrbId: string | undefined,
targetMediaElementText: string | undefined,
targetMediaElementTextPos: number[] | undefined
) => {
const dispatcherObjects: YellowTextDispatcher = { const dispatcherObjects: YellowTextDispatcher = {
moveUp: { moveUp: {
action: animateYellowTextWithMove, action: animateYellowTextWithMove,
@ -148,29 +193,53 @@ const YellowTextStateManager = (props: any) => {
action: animateYellowTextWithoutMove, action: animateYellowTextWithoutMove,
value: [targetBlueOrbHudId, targetBlueOrbId], value: [targetBlueOrbHudId, targetBlueOrbId],
}, },
setActivePlay: {
action: animateMediaYellowText,
value: [targetMediaElementText, targetMediaElementTextPos],
},
setActiveExit: {
action: animateMediaYellowText,
value: [targetMediaElementText, targetMediaElementTextPos],
},
}; };
return dispatcherObjects[event as keyof typeof dispatcherObjects]; return dispatcherObjects[event as keyof typeof dispatcherObjects];
}, },
[animateYellowTextWithMove, animateYellowTextWithoutMove] [
animateYellowTextWithMove,
animateYellowTextWithoutMove,
animateMediaYellowText,
]
); );
useEffect(() => { useEffect(() => {
if (props.eventState) { if (props.eventState) {
const eventObject = const eventObject: EventObject =
blue_orb_directions[ blue_orb_directions[
props.eventState as keyof typeof blue_orb_directions props.eventState as keyof typeof blue_orb_directions
] ||
media_scene_directions[
props.eventState as keyof typeof media_scene_directions
]; ];
if (eventObject) { if (eventObject) {
const eventAction = eventObject.action; const eventAction = eventObject.action;
// main scene specific
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

@ -2,7 +2,7 @@ import orangeFont from "../../static/sprite/orange_font_texture.png";
import yellowFont from "../../static/sprite/yellow_font_texture.png"; import yellowFont from "../../static/sprite/yellow_font_texture.png";
import * as THREE from "three"; import * as THREE from "three";
import { useLoader } from "react-three-fiber"; import { useLoader } from "react-three-fiber";
import orange_font_json from "../../resources/orange_font.json"; import orange_font_json from "../../resources/big_font.json";
import { a, useSpring } from "@react-spring/three"; import { a, useSpring } from "@react-spring/three";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { LetterProps } from "./TextRenderer"; import { LetterProps } from "./TextRenderer";
@ -48,7 +48,7 @@ const BigLetter = (props: BigLetterProps) => {
const lineYOffsets = { const lineYOffsets = {
1: 0.884, 1: 0.884,
2: 0.765, 2: 0.765,
3: 0.65, 3: 0.648,
4: 0.47, 4: 0.47,
}; };
@ -70,14 +70,13 @@ const BigLetter = (props: BigLetterProps) => {
v = v =
(v * letterData[3]) / 136 + (v * letterData[3]) / 136 +
letterData[4] / 136 + lineYOffsets[getLineNum(props.letter)] -
lineYOffsets[getLineNum(props.letter) as keyof typeof lineYOffsets] -
letterData[4] / 136; letterData[4] / 136;
uvAttribute.setXY(i, u, v); uvAttribute.setXY(i, u, v);
} }
return geometry; return geometry;
}, []); }, [letterData, lineYOffsets, props.letter]);
const textRendererState = useSpring({ const textRendererState = useSpring({
letterOffsetXCoeff: letterOffsetXCoeff:
@ -92,8 +91,8 @@ const BigLetter = (props: BigLetterProps) => {
return ( return (
<a.mesh <a.mesh
position-x={textRendererState.letterOffsetXCoeff} position-x={textRendererState.letterOffsetXCoeff}
position-y={props.letterIdx === 0 ? -0.03 : 0} position-y={props.letterIdx === 0 ? -0.03 : 0 - letterData[4] / 12.5}
scale={props.letterIdx === 0 ? [1.7, 1, 1.7] : [1, 1, 1]} scale={props.letterIdx === 0 ? [1.5, 1, 1.5] : [1, 1, 1]}
geometry={geom} geometry={geom}
renderOrder={props.letterIdx === 0 ? 4 : 3} renderOrder={props.letterIdx === 0 ? 4 : 3}
> >

View file

@ -60,7 +60,6 @@ const MediumLetter = (props: LetterProps) => {
v = v =
(v * letterData[3]) / 136 + (v * letterData[3]) / 136 +
letterData[4] / 136 +
lineYOffsets[getLineNum(props.letter)] - lineYOffsets[getLineNum(props.letter)] -
letterData[4] / 136; letterData[4] / 136;
@ -73,6 +72,7 @@ const MediumLetter = (props: LetterProps) => {
return ( return (
<a.mesh <a.mesh
position-x={props.letterIdx * 1.6} position-x={props.letterIdx * 1.6}
position-y={0 - letterData[4] / 12.5}
scale={[1.7, 1, 1.7]} scale={[1.7, 1, 1.7]}
geometry={geom} geometry={geom}
renderOrder={100} renderOrder={100}

View file

@ -44,7 +44,7 @@ const TextRenderer = () => {
// ==================================== GREEN TEXT ============================================ // ==================================== GREEN TEXT ============================================
const greenText = useTextRendererStore((state) => state.greenText); const greenText = useTextRendererStore((state) => state.greenText);
const greenTextArr = useMemo(() => greenText.split(""), []); const greenTextArr = useMemo(() => greenText.split(""), [greenText]);
const greenTextActive = useTextRendererStore( const greenTextActive = useTextRendererStore(
(state) => state.greenTextActive (state) => state.greenTextActive
); );

View file

@ -47,10 +47,10 @@
"f": [90, 34, 9, 14, 3], "f": [90, 34, 9, 14, 3],
"g": [100, 34, 11, 17, 0], "g": [100, 34, 11, 17, 0],
"h": [112, 34, 11, 14, 0], "h": [112, 34, 11, 14, 0],
"i": [125, 34, 4, 14, 0], "i": [123, 34, 7, 14, 0],
"j": [132, 34, 7, 17, 3], "j": [132, 34, 7, 17, 3],
"k": [140, 34, 11, 14, 0], "k": [140, 34, 11, 14, 0],
"l": [153, 34, 4, 14, 0], "l": [152, 34, 7, 15, 0],
"m": [160, 34, 14, 14, 0], "m": [160, 34, 14, 14, 0],
"n": [176, 34, 11, 14, 0], "n": [176, 34, 11, 14, 0],
"o": [188, 34, 12, 14, 0], "o": [188, 34, 12, 14, 0],
@ -63,7 +63,7 @@
"v": [22, 58, 13, 14, 0], "v": [22, 58, 13, 14, 0],
"w": [36, 58, 17, 14, 0], "w": [36, 58, 17, 14, 0],
"x": [54, 58, 11, 14, 0], "x": [54, 58, 11, 14, 0],
"y": [66, 58, 13, 17, 3], "y": [65, 58, 13, 14, 3],
"z": [80, 58, 10, 14, 0], "z": [80, 58, 10, 14, 0],
",": [92, 58, 5, 16, 2], ",": [92, 58, 5, 16, 2],
".": [100, 58, 5, 14, 0], ".": [100, 58, 5, 14, 0],

View file

@ -1,14 +1,14 @@
{ {
"play_down": { "play_down": {
"action": "setActiveMediaElement", "action": "setActivePlay",
"target_media_element": "exit", "target_media_element": "exit",
"target_media_element_text": "Exit", "target_media_element_text": "Exit",
"target_media_element_text_position": [-3.5, -1.6, 0.6] "target_media_element_text_position": [-0.8, -0.08, 0.6]
}, },
"exit_up": { "exit_up": {
"action": "setActiveMediaElement", "action": "setActiveExit",
"target_media_element": "play", "target_media_element": "play",
"target_media_element_text": "Play", "target_media_element_text": "Play",
"target_media_element_text_position": [-2.7, -0.9, 0.6] "target_media_element_text_position": [-0.8, 0.05, 0.6]
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -114,7 +114,7 @@ type TextRendererState = {
export const useTextRendererStore = create<TextRendererState>((set) => ({ export const useTextRendererStore = create<TextRendererState>((set) => ({
// yellow text // yellow text
yellowText: "Tda028", yellowText: "Play",
yellowTextPosY: 0.23, yellowTextPosY: 0.23,
yellowTextPosX: -0.35, yellowTextPosX: -0.35,
yellowTextOffsetXCoeff: 0, yellowTextOffsetXCoeff: 0,