end scene done + replacing some settimeouts with sleeps

This commit is contained in:
ad044 2021-02-14 20:14:41 +04:00
parent fcc029fc56
commit d63d11585b
14 changed files with 261 additions and 151 deletions

View file

@ -8,6 +8,7 @@ import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainAnimator } from "three-plain-animator/lib/plain-animator";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../store";
const EndSelectionScreen = () => {
const middleSpritesheetTex: any = useLoader(
@ -22,6 +23,8 @@ const EndSelectionScreen = () => {
const continueTextTex = useLoader(THREE.TextureLoader, continueText);
const middleLainTex = useLoader(THREE.TextureLoader, middleLain);
const componentMatrixIdx = useStore((state) => state.endComponentMatrixIdx);
const [middleSpritesheetAnimator] = useState(() => {
const anim = new PlainAnimator(middleSpritesheetTex, 1, 4, 4, 24);
anim.init(0);
@ -71,7 +74,10 @@ const EndSelectionScreen = () => {
<boxBufferGeometry attach="geometry" />
<meshBasicMaterial attach="material" color={0x000000} />
</mesh>
<sprite position={[0, 1, 0]} scale={[0.5, 0.5, 0]}>
<sprite
position={componentMatrixIdx === 0 ? [0, 1, 0] : [0, -1.5, 0]}
scale={[0.5, 0.5, 0]}
>
<spriteMaterial attach="material" map={circleSpritesheetTex} />
</sprite>
<sprite position={[0, 1.6, 0]} scale={[1.5, 0.5, 0]}>

View file

@ -1,15 +1,13 @@
import React, { useEffect, useState } from "react";
import { useStore } from "../../store";
import { useStore } from "../store";
import { a, useSpring } from "@react-spring/three";
import dummy from "../../static/sprite/dummy.png";
import dummy from "../static/sprite/dummy.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
const Images = () => {
const idleNodeImages = useStore((state) => state.idleImages);
const nodeImages = useStore(
(state) => state.activeNode.image_table_indices
);
const nodeImages = useStore((state) => state.activeNode.image_table_indices);
const currentScene = useStore((state) => state.currentScene);
@ -49,7 +47,7 @@ const Images = () => {
imgTries++;
if (img[1] !== "-1") {
import(
"../../static/media_images/" + currentSite + "/" + img[1] + ".png"
"../static/media_images/" + currentSite + "/" + img[1] + ".png"
).then((imageSrc: { default: string }) => {
imgArr.splice(parseInt(img[0]), 0, imageSrc);
if (imgTries === 3) {

View file

@ -1,6 +1,7 @@
import { useCallback, useEffect, useMemo, useRef } from "react";
import {
getBootSceneContext,
getEndSceneContext,
getMainSceneContext,
getMediaSceneContext,
getSSknSceneContext,
@ -33,6 +34,8 @@ 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";
import handleEndSceneKeyPress from "../core/scene-keypress-handlers/handleEndSceneKeyPress";
import endManager from "../core/setters/end/endManager";
const KeyPressHandler = () => {
const mediaSceneSetters = useMemo(
@ -83,6 +86,11 @@ const KeyPressHandler = () => {
[]
);
const endSceneSetters = useMemo(
() => [sceneManager, soundManager, endManager],
[]
);
const scene = useStore((state) => state.currentScene);
const mainSubscene = useStore((state) => state.mainSubscene);
@ -157,6 +165,12 @@ const KeyPressHandler = () => {
handler: handleBootSceneKeyPress,
setters: bootSceneSetters,
};
case "end":
return {
contextProvider: getEndSceneContext,
handler: handleEndSceneKeyPress,
setters: endSceneSetters,
};
case "gate":
case "polytan":
return {
@ -191,6 +205,7 @@ const KeyPressHandler = () => {
},
[
bootSceneSetters,
endSceneSetters,
mainSceneSetters,
mediaSceneSetters,
scene,

View file

@ -7,6 +7,7 @@ import { useStore } from "../../store";
import MiddleRingPart from "./MiddleRing/MiddleRingPart";
import usePrevious from "../../hooks/usePrevious";
import lerp from "../../utils/lerp";
import sleep from "../../utils/sleep";
const MiddleRing = () => {
const middleRingTex = useLoader(THREE.TextureLoader, middleRingTexture);
@ -216,94 +217,79 @@ const MiddleRing = () => {
const prevData = usePrevious({ siteRotY, activeLevel, subscene });
useEffect(() => {
const rotate = (rotValues: [number, number]) => {
setTimeout(() => {
setRot({ rotZ: rotValues[0] });
}, 2300);
const rotate = async (rotValues: [number, number]) => {
await sleep(2300);
setRot({ rotZ: rotValues[0] });
setTimeout(() => {
setRot({ rotZ: rotValues[1] });
}, 3500);
await sleep(1200);
setRot({ rotZ: rotValues[1] });
setTimeout(() => {
setRot({ rotZ: 0 });
}, 4500);
await sleep(1000);
setRot({ rotZ: 0 });
};
const moveDown = () => {
setTimeout(() => {
setNoiseAmp(0.06);
setRotating(false);
}, 800);
const moveDown = async () => {
await sleep(800);
setNoiseAmp(0.06);
setRotating(false);
setTimeout(() => {
setPos({ posY: 1.39 });
}, 1200);
await sleep(400);
setPos({ posY: 1.39 });
// set ring rotation on x axis to craete motion effect
setTimeout(() => {
setRot({ rotX: 0.3 });
}, 1500);
await sleep(300);
setRot({ rotX: 0.3 });
setTimeout(() => {
setPos({ posY: -0.31 });
}, 3000);
await sleep(1500);
setPos({ posY: -0.31 });
setTimeout(() => {
setPos({ posY: -0.11 });
}, 3150);
await sleep(150);
setPos({ posY: -0.11 });
// rotate it again, set ring noise to 0
setTimeout(() => {
setRot({ rotX: -0.1 });
setNoiseAmp(0);
}, 3500);
await sleep(350);
setRot({ rotX: -0.1 });
setNoiseAmp(0);
// rotate it back AGAIN (holy fuk psx game)
setTimeout(() => {
setRot({ rotX: 0.05 });
}, 4500);
await sleep(1000);
setRot({ rotX: 0.05 });
// reset value, set noise to 0
setTimeout(() => {
setRot({ rotX: 0, rotZ: 0 });
setRotating(true);
}, 4800);
await sleep(300);
setRot({ rotX: 0, rotZ: 0 });
setRotating(true);
// enable noise again in about 11-12 secs
setTimeout(() => {
setNoiseAmp(0.03);
}, 11600);
// enable noise again
await sleep(6000);
setNoiseAmp(0.03);
};
const moveUp = () => {
const moveUp = async () => {
// change noise to 0, make the ring bend downwards
setTimeout(() => {
setNoiseAmp(0);
setWobbleAmp(0.2);
}, 300);
await sleep(300);
setNoiseAmp(0);
setWobbleAmp(0.2);
// disable rotation of the ring
setTimeout(() => {
setRotating(false);
}, 700);
await sleep(400);
setRotating(false);
// make the ring bend upwards
setTimeout(() => {
setWobbleAmp(-0.3);
// the middle ring stays in place, therefore we animate it
// in the same direction as the site, creating that illusion.
setPos({ posY: -1.39 });
}, 1200);
await sleep(500);
setWobbleAmp(-0.3);
// the middle ring stays in place, therefore we animate it
// in the same direction as the site, creating that illusion.
setPos({ posY: -1.39 });
await sleep(300);
// reset the ring bend, set the rotation to slightly curve
// to replicate a motion effect (since its moving upwards)
// and enable rotation again
setTimeout(() => {
setWobbleAmp(0);
setRot({ rotX: -0.2 });
setRotating(true);
}, 1500);
setWobbleAmp(0);
setRot({ rotX: -0.2 });
setRotating(true);
setTimeout(() => {
setPos({ posY: 0.09 });

View file

@ -3,7 +3,7 @@ import * as THREE from "three";
import greenFont from "../../static/sprite/white_and_green_texture.png";
import medium_font_json from "../../resources/font_data/medium_font.json";
import { a } from "@react-spring/three";
import React, { memo, useCallback, useMemo } from "react";
import React, { memo, useCallback, useEffect, useMemo } from "react";
import { useStore } from "../../store";
const GreenTextRenderer = memo(() => {

View file

@ -0,0 +1,15 @@
const handleEndSceneKeyPress = (endSceneContext: any) => {
const { keyPress, selectionVisible, activeEndComponent } = endSceneContext;
if (selectionVisible) {
switch (keyPress) {
case "UP":
case "DOWN":
return { event: `end_selection_${keyPress.toLowerCase()}` };
case "CIRCLE":
return { event: `end_${activeEndComponent}_select` };
}
}
};
export default handleEndSceneKeyPress;

View file

@ -0,0 +1,26 @@
import { useStore } from "../../../store";
const endManager = (eventState: any) => {
const setComponentMatrixIdx = useStore.getState().setEndComponentMatrixIdx;
const dispatchAction = (eventState: { event: string }) => {
switch (eventState.event) {
case "end_selection_up":
return {
action: () => setComponentMatrixIdx(0),
};
case "end_selection_down":
return {
action: () => setComponentMatrixIdx(1),
};
}
};
const { action } = { ...dispatchAction(eventState) };
if (action) {
action();
}
};
export default endManager;

View file

@ -65,6 +65,7 @@ const sceneManager = (eventState: any) => {
delay: 6000,
};
case "pause_change_select":
case "end_continue_select":
return {
action: () =>
useStore.setState({ currentScene: "change_disc", intro: true }),
@ -81,6 +82,11 @@ const sceneManager = (eventState: any) => {
action: () => useStore.setState({ currentScene: "main" }),
delay: 0,
};
case "end_end_select":
return {
action: () => useStore.setState({ currentScene: "boot" }),
delay: 0,
};
}
};

View file

@ -1,42 +1,39 @@
import { playAudio } from "../../store";
import * as audio from "../../static/sfx";
import sleep from "../../utils/sleep";
const soundManager = (eventState: any) => {
const dispatchAction = (eventState: { event: string; scene: string }) => {
switch (eventState.event) {
case "knock_and_fall":
return {
action: () => {
setTimeout(() => {
playAudio(audio.sound14);
}, 1200);
action: async () => {
await sleep(1200);
playAudio(audio.sound14);
setTimeout(() => {
playAudio(audio.sound19);
}, 2300);
await sleep(1100);
setTimeout(() => {
playAudio(audio.sound33);
}, 3150);
playAudio(audio.sound19);
await sleep(850);
playAudio(audio.sound33);
},
};
case "knock":
return {
action: () => {
setTimeout(() => {
playAudio(audio.sound18);
}, 1200);
action: async () => {
await sleep(1200);
playAudio(audio.sound18);
},
};
case "touch_and_scare":
return {
action: () => {
setTimeout(() => {
playAudio(audio.sound17);
}, 2400);
setTimeout(() => {
playAudio(audio.sound33);
}, 3150);
action: async () => {
await sleep(2400);
playAudio(audio.sound17);
await sleep(750);
playAudio(audio.sound33);
},
};
case "throw_node_media":
@ -45,17 +42,15 @@ const soundManager = (eventState: any) => {
case "throw_node_tak":
case "throw_node_polytan":
return {
action: () => {
action: async () => {
playAudio(audio.sound0);
setTimeout(() => {
playAudio(audio.sound12);
}, 1600);
await sleep(1600);
playAudio(audio.sound12);
setTimeout(() => {
playAudio(audio.sound13);
playAudio(audio.sound14);
}, 2800);
await sleep(1200);
playAudio(audio.sound13);
playAudio(audio.sound14);
},
};
case "rip_node_media":
@ -64,17 +59,15 @@ const soundManager = (eventState: any) => {
case "rip_node_tak":
case "rip_node_polytan":
return {
action: () => {
action: async () => {
playAudio(audio.sound0);
setTimeout(() => {
playAudio(audio.sound12);
}, 1600);
await sleep(1600);
playAudio(audio.sound12);
setTimeout(() => {
playAudio(audio.sound15);
playAudio(audio.sound13);
}, 4000);
await sleep(2400);
playAudio(audio.sound15);
playAudio(audio.sound13);
},
};
@ -86,55 +79,53 @@ const soundManager = (eventState: any) => {
case "pause_about_select":
case "display_prompt":
case "pause_exit_select":
case "end_continue_select":
case "end_end_select":
return {
action: () => playAudio(audio.sound0),
};
case "site_left":
case "site_right":
return {
action: () => {
setTimeout(() => {
playAudio(audio.sound6);
playAudio(audio.sound34);
}, 1100);
action: async () => {
await sleep(1100);
playAudio(audio.sound6);
playAudio(audio.sound34);
},
};
case "pause_game":
return {
action: () => {
action: async () => {
playAudio(audio.sound7);
setTimeout(() => {
playAudio(audio.sound23);
}, 3400);
await sleep(3400);
playAudio(audio.sound23);
},
};
case "select_level_up":
case "select_level_down":
return {
action: () => {
setTimeout(() => {
playAudio(audio.sound10);
playAudio(audio.sound9);
}, 1300);
action: async () => {
await sleep(1300);
playAudio(audio.sound10);
playAudio(audio.sound9);
setTimeout(() => {
playAudio(audio.sound8);
}, 2700);
await sleep(1400);
playAudio(audio.sound8);
},
};
case "site_up":
case "site_down":
return {
action: () => {
action: async () => {
playAudio(audio.sound13);
setTimeout(() => {
playAudio(audio.sound10);
playAudio(audio.sound9);
}, 1300);
setTimeout(() => {
playAudio(audio.sound8);
}, 2700);
await sleep(1300);
playAudio(audio.sound10);
playAudio(audio.sound9);
await sleep(1400);
playAudio(audio.sound8);
},
};
case "main_menu_down":
@ -150,6 +141,8 @@ const soundManager = (eventState: any) => {
case "media_leftside_up":
case "media_rightside_down":
case "media_rightside_up":
case "end_selection_up":
case "end_selection_down":
return {
action: () => playAudio(audio.sound1),
};

View file

@ -1,4 +1,10 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import { createAudioAnalyser, useStore } from "../store";
@ -15,6 +21,9 @@ const EndScene = () => {
const mainCylinderRef = useRef<THREE.Object3D>();
const setAudioAnalyser = useStore((state) => state.setAudioAnalyser);
const setSelectionVisible = useStore(
(state) => state.setEndSceneSelectionVisible
);
useFrame(() => {
if (mainCylinderRef.current) {
@ -33,10 +42,12 @@ const EndScene = () => {
const [isIntro, setIsIntro] = useState(false);
const [isOutro, setIsOutro] = useState(false);
const [sceneOutro, setSceneOutro] = useState(false);
const [showSelectionScreen, setShowSelectionScreen] = useState(false);
const playedMediaCountRef = useRef(0);
const mediaList = useMemo(() => [Xa0001, Xa0006], []);
const playerName = useStore((state) => state.playerName);
const playerNameVoices = useMemo(() => playerName.split(""), [playerName]);
useEffect(() => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
@ -57,7 +68,22 @@ const EndScene = () => {
}, 3800);
}
if (playedMediaCountRef.current === mediaList.length) {
if (
playedMediaCountRef.current > 1 &&
playedMediaCountRef.current < playerNameVoices.length + 1
) {
import(
"../static/voice/" +
playerNameVoices[playedMediaCountRef.current - 1] +
".WAV"
).then((media) => {
mediaElement.src = media.default;
mediaElement.load();
mediaElement.play();
});
}
if (playedMediaCountRef.current === playerNameVoices.length + 1) {
mediaElement.src = Xa0006;
mediaElement.load();
@ -66,11 +92,17 @@ const EndScene = () => {
setTimeout(() => {
setSceneOutro(true);
}, 4000);
setTimeout(() => {
setObjectsVisible(false);
setShowSelectionScreen(true);
setSelectionVisible(true);
}, 7000);
}
};
mediaElement.addEventListener("ended", playNextMedia);
}, [mediaList]);
}, [playerNameVoices, setSelectionVisible]);
useEffect(() => {
const mediaElement = document.getElementById("media") as HTMLMediaElement;
@ -89,20 +121,25 @@ const EndScene = () => {
}, [setAudioAnalyser]);
return (
<group visible={objectsVisible}>
<pointLight position={[0, 0, 5]} intensity={0.9} />
<pointLight position={[0, 0, -5]} intensity={0.9} />
<>
<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 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>
<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>
<group visible={showSelectionScreen}>
<EndSelectionScreen />
</group>
</>
);
};

View file

@ -1,6 +1,6 @@
import React, { useEffect } from "react";
import { useStore } from "../store";
import Images from "../components/MediaScene/Images";
import Images from "../components/Images";
const IdleMediaScene = () => {
const mediaPercentageElapsed = useStore(

View file

@ -5,7 +5,7 @@ import RightSide from "../components/MediaScene/Selectables/RightSide";
import AudioVisualizer from "../components/MediaScene/AudioVisualizer/AudioVisualizer";
import MediaLoadingBar from "../components/MediaScene/MediaLoadingBar";
import NodeNameContainer from "../components/MediaScene/NodeNameContainer";
import Images from "../components/MediaScene/Images";
import Images from "../components/Images";
import GreenTextRenderer from "../components/TextRenderer/GreenTextRenderer";
import MediaYellowTextAnimator from "../components/TextRenderer/MediaYellowTextAnimator";

View file

@ -40,6 +40,11 @@ type State = {
// level selection
selectedLevel: number;
// end scene
endComponentMatrix: ["end", "continue"];
endComponentMatrixIdx: 0 | 1;
endSceneSelectionVisible: boolean;
// pause
pauseComponentMatrix: ["load", "about", "change", "save", "exit"];
pauseComponentMatrixIdx: number;
@ -121,7 +126,7 @@ export const useStore = create(
combine(
{
// scene data
currentScene: "media",
currentScene: "boot",
// game progress
gameProgress: game_progress,
@ -163,6 +168,11 @@ export const useStore = create(
// level selection
selectedLevel: 4,
// end scene
endComponentMatrix: ["end", "continue"],
endComponentMatrixIdx: 0,
endSceneSelectionVisible: false,
// pause
pauseComponentMatrix: ["load", "about", "change", "save", "exit"],
pauseComponentMatrixIdx: 2,
@ -215,7 +225,7 @@ export const useStore = create(
gateLvl: 0,
// player name
playerName: "",
playerName: "アイウエオ",
// boot scene
mainMenuComponentMatrix: ["authorize_user", "load_data"],
@ -303,6 +313,12 @@ export const useStore = create(
// level selection setters
setSelectedLevel: (to: number) => set(() => ({ selectedLevel: to })),
// end scene setters
setEndComponentMatrixIdx: (to: 0 | 1) =>
set(() => ({ endComponentMatrixIdx: to })),
setEndSceneSelectionVisible: (to: boolean) =>
set(() => ({ endSceneSelectionVisible: to })),
// pause setters
setPauseComponentMatrixIdx: (to: number) =>
set(() => ({ pauseComponentMatrixIdx: to })),
@ -519,6 +535,15 @@ export const getBootSceneContext = () => {
};
};
export const getEndSceneContext = () => {
const state = useStore.getState();
return {
activeEndComponent: state.endComponentMatrix[state.endComponentMatrixIdx],
selectionVisible: state.endSceneSelectionVisible,
};
};
export const playAudio = (audio: HTMLAudioElement) => {
audio.currentTime = 0;
audio.currentTime = 0;

3
src/utils/sleep.ts Normal file
View file

@ -0,0 +1,3 @@
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
export default sleep;