end scene almost done

This commit is contained in:
ad044 2021-02-14 00:03:39 +04:00
parent 6c9a229541
commit fcc029fc56
10 changed files with 215 additions and 110 deletions

View file

@ -45,7 +45,7 @@ const App = () => {
<Canvas concurrent>
<KeyPressHandler />
<Suspense fallback={null}>
<Preloader />
{/*<Preloader />*/}
{dispatchScene[currentScene as keyof typeof dispatchScene]}
</Suspense>
</Canvas>

View file

@ -4,6 +4,7 @@ import {
getMainSceneContext,
getMediaSceneContext,
getSSknSceneContext,
playAudio,
useStore,
} from "../store";
import { getKeyCodeAssociation } from "../utils/keyPressUtils";
@ -31,6 +32,7 @@ import soundManager from "../core/setters/soundManager";
import { useFrame } from "react-three-fiber";
import { getRandomIdleLainAnim, getRandomIdleMedia } from "../utils/idle-utils";
import idleManager from "../core/setters/main/idleManager";
import * as audio from "../static/sfx";
const KeyPressHandler = () => {
const mediaSceneSetters = useMemo(
@ -96,13 +98,14 @@ const KeyPressHandler = () => {
mainSubscene !== "level_selection" &&
scene === "main"
) {
// if (now > lainIdleCounter.current + 10000) {
// lainManager({ event: getRandomIdleLainAnim() });
// // after one idle animation plays, the second comes sooner than it would after a regular keypress
// lainIdleCounter.current = now - 2500;
// }
if (now > lainIdleCounter.current + 10000) {
lainManager({ event: getRandomIdleLainAnim() });
// after one idle animation plays, the second comes sooner than it would after a regular keypress
lainIdleCounter.current = now - 2500;
}
// if (now > idleSceneCounter.current + 5000) {
// idleManager(getRandomIdleMedia());
// playAudio(audio.sound32);
// setTimeout(() => {
// sceneManager({ event: "play_idle_media" });
// }, 1200);
@ -124,8 +127,10 @@ const KeyPressHandler = () => {
const now = Date.now();
if (keyPress) {
lainIdleCounter.current = now;
idleSceneCounter.current = now;
if (scene === "main") {
lainIdleCounter.current = now;
idleSceneCounter.current = now;
}
const sceneFns = (() => {
switch (scene) {
case "main":
@ -157,6 +162,14 @@ const KeyPressHandler = () => {
return {
action: () => useStore.setState({ currentScene: "main" }),
};
case "idle_media":
return {
action: () =>
useStore.setState({
currentScene: "main",
idleStarting: false,
}),
};
}
})();

View file

@ -4,6 +4,9 @@ import { useStore } from "../store";
const MediaPlayer = () => {
const setPercentageElapsed = useStore((state) => state.setPercentageElapsed);
// use it as a guard to avoid multiple set states inside updateTime
const lastSetPercentageRef = useRef<undefined | number>(undefined);
const requestRef = useRef();
const videoRef = createRef<HTMLVideoElement>();
const trackRef = createRef<HTMLTrackElement>();
@ -35,8 +38,12 @@ const MediaPlayer = () => {
const duration = videoRef.current.duration;
const percentageElapsed = Math.floor((timeElapsed / duration) * 100);
if (percentageElapsed % 5 === 0 && percentageElapsed !== 0) {
if (
percentageElapsed % 5 === 0 &&
lastSetPercentageRef.current !== percentageElapsed
) {
setPercentageElapsed(percentageElapsed);
lastSetPercentageRef.current = percentageElapsed;
}
}
}, [setPercentageElapsed, videoRef]);

View file

@ -5,11 +5,8 @@ import standingSpriteSheet from "../static/sprite/standing.png";
import moveLeftSpriteSheet from "../static/sprite/move_left.png";
import moveRightSpriteSheet from "../static/sprite/move_right.png";
import bigHudSpriteSheet from "../static/sprite/big_hud.png";
import bigHudMirroredSpriteSheet from "../static/sprite/big_hud_mirrored.png";
import longHudSpriteSheet from "../static/sprite/long_hud.png";
import longHudMirroredSpriteSheet from "../static/sprite/long_hud_mirrored.png";
import boringHudSpriteSheet from "../static/sprite/long_hud_boring.png";
import boringHudMirroredSpriteSheet from "../static/sprite/long_hud_boring_mirrored.png";
import throwNodeSpriteSheet from "../static/sprite/throw_node.png";
import ripMiddleRingSpriteSheet from "../static/sprite/rip_middle_ring.png";
import ripNodeSpriteSheet from "../static/sprite/rip_node.png";
@ -17,14 +14,30 @@ import prayerSpriteSheet from "../static/sprite/prayer.png";
import knockSpriteSheet from "../static/sprite/knock.png";
import knockAndFallSpriteSheet from "../static/sprite/knock_and_fall.png";
import touchAndScareSpriteSheet from "../static/sprite/touch_and_scare.png";
import touchSleeveSpriteSheet from "../static/sprite/touch_sleeve.png";
import thinkingSpriteSheet from "../static/sprite/thinking.png";
import stretchSpriteSheet from "../static/sprite/stretch.png";
import stretch2SpriteSheet from "../static/sprite/stretch_2.png";
import spinSpriteSheet from "../static/sprite/spin.png";
import scratchHeadSpriteSheet from "../static/sprite/scratch_head.png";
import blushSpriteSheet from "../static/sprite/blush.png";
import handsBehindHeadSpriteSheet from "../static/sprite/hands_behind_head.png";
import handsOnHipsSpriteSheet from "../static/sprite/hands_on_hips.png";
import handsOnHips2SpriteSheet from "../static/sprite/hands_on_hips_2.png";
import handsTogetherSpriteSheet from "../static/sprite/hands_together.png";
import leanForwardSpriteSheet from "../static/sprite/lean_forward.png";
import leanLeftSpriteSheet from "../static/sprite/lean_left.png";
import leanRightSpriteSheet from "../static/sprite/lean_right.png";
import lookAroundSpriteSheet from "../static/sprite/look_around.png";
import playWithHairSpriteSheet from "../static/sprite/play_with_hair.png";
import * as THREE from "three";
import { useLoader, useThree } from "react-three-fiber";
import { useLayoutEffect } from "react";
import { memo, useLayoutEffect } from "react";
// this function just preloads lain's spritesheets and other assets cuz they're big and lazy loading them
// used to make the suspense run for a couple milliseconds, resulting in flickering
const Preloader = () => {
const Preloader = memo(() => {
const intro = useLoader(THREE.TextureLoader, introSpriteSheet);
const moveDown = useLoader(THREE.TextureLoader, moveDownSpriteSheet);
const moveUp = useLoader(THREE.TextureLoader, moveUpSpriteSheet);
@ -33,20 +46,8 @@ const Preloader = () => {
const stand = useLoader(THREE.TextureLoader, standingSpriteSheet);
const throwNode = useLoader(THREE.TextureLoader, throwNodeSpriteSheet);
const bigHud = useLoader(THREE.TextureLoader, bigHudSpriteSheet);
const bigHudMirrored = useLoader(
THREE.TextureLoader,
bigHudMirroredSpriteSheet
);
const longHud = useLoader(THREE.TextureLoader, longHudSpriteSheet);
const longHudMirrored = useLoader(
THREE.TextureLoader,
longHudMirroredSpriteSheet
);
const boringHud = useLoader(THREE.TextureLoader, boringHudSpriteSheet);
const boringHudMirrored = useLoader(
THREE.TextureLoader,
boringHudMirroredSpriteSheet
);
const ripMiddleRing = useLoader(
THREE.TextureLoader,
ripMiddleRingSpriteSheet
@ -59,6 +60,28 @@ const Preloader = () => {
THREE.TextureLoader,
touchAndScareSpriteSheet
);
const touchSleeve = useLoader(THREE.TextureLoader, touchSleeveSpriteSheet);
const thinking = useLoader(THREE.TextureLoader, thinkingSpriteSheet);
const stretch = useLoader(THREE.TextureLoader, stretchSpriteSheet);
const stretch2 = useLoader(THREE.TextureLoader, stretch2SpriteSheet);
const spinSprite = useLoader(THREE.TextureLoader, spinSpriteSheet);
const scratchHead = useLoader(THREE.TextureLoader, scratchHeadSpriteSheet);
const blush = useLoader(THREE.TextureLoader, blushSpriteSheet);
const handsBehindHead = useLoader(
THREE.TextureLoader,
handsBehindHeadSpriteSheet
);
const handsOnHips = useLoader(THREE.TextureLoader, handsOnHipsSpriteSheet);
const handsOnHips2 = useLoader(THREE.TextureLoader, handsOnHips2SpriteSheet);
const handsTogether = useLoader(
THREE.TextureLoader,
handsTogetherSpriteSheet
);
const leanForward = useLoader(THREE.TextureLoader, leanForwardSpriteSheet);
const leanLeft = useLoader(THREE.TextureLoader, leanLeftSpriteSheet);
const leanRight = useLoader(THREE.TextureLoader, leanRightSpriteSheet);
const lookAround = useLoader(THREE.TextureLoader, lookAroundSpriteSheet);
const playWithHair = useLoader(THREE.TextureLoader, playWithHairSpriteSheet);
const { gl } = useThree();
useLayoutEffect(() => {
@ -70,10 +93,7 @@ const Preloader = () => {
gl.initTexture(stand);
gl.initTexture(longHud);
gl.initTexture(bigHud);
gl.initTexture(bigHudMirrored);
gl.initTexture(longHudMirrored);
gl.initTexture(boringHud);
gl.initTexture(boringHudMirrored);
gl.initTexture(throwNode);
gl.initTexture(ripMiddleRing);
gl.initTexture(ripNode);
@ -81,6 +101,22 @@ const Preloader = () => {
gl.initTexture(touchAndScare);
gl.initTexture(knock);
gl.initTexture(knockAndFall);
gl.initTexture(touchSleeve);
gl.initTexture(thinking);
gl.initTexture(stretch);
gl.initTexture(stretch2);
gl.initTexture(spinSprite);
gl.initTexture(scratchHead);
gl.initTexture(blush);
gl.initTexture(handsBehindHead);
gl.initTexture(leanForward);
gl.initTexture(leanLeft);
gl.initTexture(leanRight);
gl.initTexture(lookAround);
gl.initTexture(playWithHair);
gl.initTexture(handsOnHips);
gl.initTexture(handsOnHips2);
gl.initTexture(handsTogether);
}, [
moveDown,
moveUp,
@ -89,11 +125,8 @@ const Preloader = () => {
stand,
gl,
bigHud,
bigHudMirrored,
boringHud,
boringHudMirrored,
longHud,
longHudMirrored,
intro,
throwNode,
ripMiddleRing,
@ -102,8 +135,24 @@ const Preloader = () => {
touchAndScare,
knock,
knockAndFall,
touchSleeve,
thinking,
stretch,
stretch2,
spinSprite,
scratchHead,
blush,
handsBehindHead,
leanForward,
leanLeft,
leanRight,
lookAround,
playWithHair,
handsOnHips,
handsOnHips2,
handsTogether,
]);
return null;
};
});
export default Preloader;

View file

@ -12,10 +12,6 @@ const idleManager = (eventState: any) => {
action: () => {
setIdleStarting(true);
setIdleScene(eventState);
setTimeout(() => {
setIdleStarting(false);
}, 6000);
},
});

View file

@ -1,14 +1,21 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import { useStore } from "../store";
import { createAudioAnalyser, useStore } from "../store";
import EndSelectionScreen from "../components/EndScene/EndSelectionScreen";
import endroll from "../static/movie/ENDROLL1.STR[0].webm";
import endrollVtt from "../static/webvtt/Endroll.vtt";
import Xa0001 from "../static/audio/Xa0001.mp4";
import Xa0006 from "../static/audio/Xa0006.mp4";
import LainSpeak from "../components/LainSpeak";
import EndSphere from "../components/EndScene/EndSphere";
import EndCylinder from "../components/EndScene/EndCylinder";
const EndScene = () => {
const mediaPlayedCount = useStore((state) => state.endMediaPlayedCount);
const mainCylinderRef = useRef<THREE.Object3D>();
const setAudioAnalyser = useStore((state) => state.setAudioAnalyser);
useFrame(() => {
if (mainCylinderRef.current) {
mainCylinderRef.current.rotation.y -= 0.01;
@ -22,49 +29,81 @@ const EndScene = () => {
}
});
const [isIntro, setIsIntro] = useState(true);
const [objectsVisible, setObjectsVisible] = useState(false);
const [isIntro, setIsIntro] = useState(false);
const [isOutro, setIsOutro] = useState(false);
const [sceneOutro, setSceneOutro] = useState(false);
useEffect(() => {
if (mediaPlayedCount === 1) {
setTimeout(() => {
const mediaElement = document.getElementById(
"media"
) as HTMLMediaElement;
const playedMediaCountRef = useRef(0);
if (mediaElement) {
const mediaList = useMemo(() => [Xa0001, Xa0006], []);
useEffect(() => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
const playNextMedia = () => {
playedMediaCountRef.current++;
mediaElement.currentTime = 0;
if (playedMediaCountRef.current === 1) {
setObjectsVisible(true);
setIsIntro(true);
setTimeout(() => {
mediaElement.src = Xa0001;
mediaElement.load();
mediaElement.play();
setIsIntro(false);
}
}, 3800);
} else if (mediaPlayedCount > 1) {
setIsOutro(true);
setTimeout(() => {
setSceneOutro(true);
}, 4000);
}
}, [mediaPlayedCount]);
}, 3800);
}
// return mediaPlayedCount > 0 ? (
// <>
// <pointLight position={[0, 0, 5]} intensity={0.9} />
// <pointLight position={[0, 0, -5]} intensity={0.9} />
//
// <group ref={mainCylinderRef} position={[0, -1, 2.2]}>
// <EndCylinder />
// </group>
// <EndSphere position={[-1.8, -1.6, 1.4]} outroAnim={sceneOutro} />
// <EndSphere position={[1.8, -0.5, 0]} outroAnim={sceneOutro} />
// <EndSphere position={[2, -1.7, 1]} outroAnim={sceneOutro} />
// <EndSphere position={[-1.6, 1.4, 1.5]} outroAnim={sceneOutro} />
// <EndSphere position={[2, 1.7, -0.5]} outroAnim={sceneOutro} />
// <LainSpeak intro={isIntro} outro={isOutro} />
// </>
// ) : (
// <></>
// );
return <EndSelectionScreen />;
if (playedMediaCountRef.current === mediaList.length) {
mediaElement.src = Xa0006;
mediaElement.load();
mediaElement.play();
setIsOutro(true);
setTimeout(() => {
setSceneOutro(true);
}, 4000);
}
};
mediaElement.addEventListener("ended", playNextMedia);
}, [mediaList]);
useEffect(() => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
const trackElement = document.getElementById("track") as HTMLTrackElement;
if (mediaElement) {
setAudioAnalyser(createAudioAnalyser());
mediaElement.currentTime = 0;
trackElement.src = endrollVtt;
mediaElement.src = endroll;
mediaElement.load();
mediaElement.play();
}
}, [setAudioAnalyser]);
return (
<group visible={objectsVisible}>
<pointLight position={[0, 0, 5]} intensity={0.9} />
<pointLight position={[0, 0, -5]} intensity={0.9} />
<group ref={mainCylinderRef} position={[0, -1, 2.2]}>
<EndCylinder />
</group>
<EndSphere position={[-1.8, -1.6, 1.4]} outroAnim={sceneOutro} />
<EndSphere position={[1.8, -0.5, 0]} outroAnim={sceneOutro} />
<EndSphere position={[2, -1.7, 1]} outroAnim={sceneOutro} />
<EndSphere position={[-1.6, 1.4, 1.5]} outroAnim={sceneOutro} />
<EndSphere position={[2, 1.7, -0.5]} outroAnim={sceneOutro} />
<LainSpeak intro={isIntro} outro={isOutro} />
</group>
);
};
export default EndScene;

View file

@ -6,14 +6,17 @@ const IdleMediaScene = () => {
const mediaPercentageElapsed = useStore(
(state) => state.mediaPercentageElapsed
);
const setScene = useStore((state) => state.setScene);
const idleMedia = useStore((state) => state.idleMedia);
const idleNodeName = useStore((state) => state.idleNodeName);
useEffect(() => {
if (mediaPercentageElapsed === 100) setScene("main");
}, [mediaPercentageElapsed, setScene]);
if (mediaPercentageElapsed === 100)
useStore.setState({
currentScene: "main",
idleStarting: false,
});
}, [mediaPercentageElapsed]);
useEffect(() => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;

View file

@ -10,9 +10,13 @@ import GreenTextRenderer from "../components/TextRenderer/GreenTextRenderer";
import MediaYellowTextAnimator from "../components/TextRenderer/MediaYellowTextAnimator";
const MediaScene = () => {
const percentageElapsed = useStore((state) => state.mediaPercentageElapsed);
const setAudioAnalyser = useStore((state) => state.setAudioAnalyser);
const activeNodeMedia = useStore((state) => state.activeNode.media_file);
const activeNode = useStore((state) => state.activeNode);
const setScene = useStore((state) => state.setScene);
useEffect(() => {
document.getElementsByTagName("canvas")[0].className =
@ -23,8 +27,11 @@ const MediaScene = () => {
};
}, []);
const nodeMedia = useStore((state) => state.activeNode.media_file);
const nodeName = useStore((state) => state.activeNode.node_name);
useEffect(() => {
if (percentageElapsed === 100) {
setScene("end");
}
}, [percentageElapsed, setScene]);
useEffect(() => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
@ -34,26 +41,30 @@ const MediaScene = () => {
setAudioAnalyser(createAudioAnalyser());
mediaElement.currentTime = 0;
import("../static/webvtt/" + nodeName + ".vtt")
import("../static/webvtt/" + activeNode.node_name + ".vtt")
.then((vtt) => {
if (vtt) trackElement.src = vtt.default;
})
// some entries have no spoken words, so the file doesnt exist. we catch that here.
.catch((e) => console.log(e));
if (nodeMedia.includes("XA")) {
import("../static/audio/" + nodeMedia + ".ogg").then((media) => {
mediaElement.src = media.default;
mediaElement.load();
});
if (activeNode.media_file.includes("XA")) {
import("../static/audio/" + activeNode.media_file + ".ogg").then(
(media) => {
mediaElement.src = media.default;
mediaElement.load();
}
);
} else {
import("../static/movie/" + nodeMedia + "[0].webm").then((media) => {
mediaElement.src = media.default;
mediaElement.load();
});
import("../static/movie/" + activeNode.media_file + "[0].webm").then(
(media) => {
mediaElement.src = media.default;
mediaElement.load();
}
);
}
}
}, [nodeMedia, nodeName, setAudioAnalyser]);
}, [activeNode.media_file, activeNode.node_name, setAudioAnalyser]);
return (
<perspectiveCamera position-z={3}>
@ -69,7 +80,7 @@ const MediaScene = () => {
</group>
<MediaYellowTextAnimator />
<group visible={activeNodeMedia.includes("XA")}>
<group visible={activeNode.media_file.includes("XA")}>
<RightSide />
<AudioVisualizer />
<Images />

View file

@ -54,7 +54,7 @@ const TaKScene = () => {
setIsIntro(false);
}
}, 3800);
}, [nodeMedia, nodeName]);
}, [nodeMedia, nodeName, setAudioAnalyser]);
return <LainSpeak intro={isIntro} outro={isOutro} />;
};

View file

@ -93,9 +93,6 @@ type State = {
authorizeUserLetterIdx: number;
bootSubscene: "main_menu" | "load_data" | "authorize_user";
// end scene
endMediaPlayedCount: number;
// prompt
promptVisible: boolean;
promptComponentMatrix: ["yes", "no"];
@ -124,7 +121,7 @@ export const useStore = create(
combine(
{
// scene data
currentScene: "main",
currentScene: "media",
// game progress
gameProgress: game_progress,
@ -226,9 +223,6 @@ export const useStore = create(
authorizeUserLetterIdx: 0,
bootSubscene: "main_menu",
// end scene
endMediaPlayedCount: 0,
// prompt
promptVisible: false,
promptComponentMatrix: ["yes", "no"],
@ -395,13 +389,6 @@ export const useStore = create(
setAuthorizeUserLetterIdx: (to: number) =>
set(() => ({ authorizeUserLetterIdx: to })),
// end scene setters
incrementEndMediaPlayedCount: () =>
set((state) => ({
endMediaPlayedCount: state.endMediaPlayedCount + 1,
})),
resetEndMediaPlayedCount: () => set(() => ({ endMediaPlayedCount: 0 })),
// prompt setters
setPromptVisible: (to: boolean) => set(() => ({ promptVisible: to })),
setPromptComponentMatrixIdx: (to: 1 | 0) =>