mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
wtf
This commit is contained in:
parent
2b203fc835
commit
29ed34cd1e
21 changed files with 652 additions and 664 deletions
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -10827,6 +10827,11 @@
|
|||
"util.promisify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"recoil": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.0.10.tgz",
|
||||
"integrity": "sha512-+9gRqehw3yKETmoZbhSnWu4GO10HDb5xYf1CjLF1oXGK2uT6GX5Lu9mfTXwjxV/jXxEKx8MIRUUbgPxvbJ8SEw=="
|
||||
},
|
||||
"recursive-readdir": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "3.4.3",
|
||||
"react-three-fiber": "^4.2.20",
|
||||
"recoil": "0.0.10",
|
||||
"three": "^0.119.1",
|
||||
"three-plain-animator": "^1.0.2",
|
||||
"typescript": "^3.7.5"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import Game from "./components/Game";
|
||||
import MainScene from "./components/MainScene/MainScene";
|
||||
import "./static/css/hub.css";
|
||||
import "./static/css/main.css";
|
||||
import { Canvas } from "react-three-fiber";
|
||||
import { RecoilRoot } from "recoil";
|
||||
|
||||
const App = () => {
|
||||
const [moveToGame, setMoveToGame] = useState(false);
|
||||
|
@ -17,10 +18,12 @@ const App = () => {
|
|||
|
||||
return (
|
||||
<div id="game-root" className="game">
|
||||
{/* {moveToGame ? <Game /> : <Intro setMoveToGame={setMoveToGame} />} */}
|
||||
{/* {moveToGame ? <MainScene /> : <Intro setMoveToGame={setMoveToGame} />} */}
|
||||
{/* <Intro /> */}
|
||||
<Canvas concurrent>
|
||||
<Game />
|
||||
<RecoilRoot>
|
||||
<MainScene />
|
||||
</RecoilRoot>
|
||||
</Canvas>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,457 +0,0 @@
|
|||
import { a, useSpring } from "@react-spring/three";
|
||||
import { OrbitControls } from "drei";
|
||||
import React, {
|
||||
Suspense,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
import lain_animations from "../resources/lain_animations.json";
|
||||
import level_sprite_directions from "../resources/level_sprite_directions.json";
|
||||
import level_sprite_huds from "../resources/level_sprite_huds.json";
|
||||
import Hub from "./Hub";
|
||||
import Lain, {
|
||||
LainMoveDown,
|
||||
LainMoveLeft,
|
||||
LainMoveRight,
|
||||
LainMoveUp,
|
||||
LainStanding,
|
||||
LainIntro,
|
||||
} from "./Lain";
|
||||
import Lights from "./Lights";
|
||||
import OrthoCamera from "./OrthoCamera";
|
||||
import Preloader from "./Preloader";
|
||||
import Starfield from "./Starfield";
|
||||
import * as THREE from "three";
|
||||
|
||||
type KeyCodeAssociations = {
|
||||
[keyCode: number]: string;
|
||||
};
|
||||
|
||||
type SpriteDirectionData = {
|
||||
[direction: string]: string;
|
||||
};
|
||||
|
||||
type SpriteDirections = {
|
||||
[sprite_id: string]: SpriteDirectionData;
|
||||
};
|
||||
|
||||
type HudShapeData = {
|
||||
position: number[];
|
||||
scale: number[];
|
||||
type: string;
|
||||
initial_position: number[];
|
||||
};
|
||||
|
||||
type SpriteHudData = {
|
||||
long: HudShapeData;
|
||||
boring: HudShapeData;
|
||||
big: HudShapeData;
|
||||
};
|
||||
|
||||
type SpriteHuds = {
|
||||
[sprite_hud_id: string]: SpriteHudData;
|
||||
};
|
||||
|
||||
type LainAnimationData = {
|
||||
frame_count: number;
|
||||
duration: number;
|
||||
};
|
||||
type LainAnimations = {
|
||||
[sprite: string]: LainAnimationData;
|
||||
};
|
||||
|
||||
const Game = () => {
|
||||
const [isIntro, setIsIntro] = useState(true);
|
||||
|
||||
const [isLainMoving, setLainMoving] = useState(true);
|
||||
const [lainMoveState, setLainMoveState] = useState(<LainIntro />);
|
||||
|
||||
const [orthoCameraPosY, setOrthoCameraPosY] = useState(0);
|
||||
|
||||
const [currentSprite, setCurrentSprite] = useState("0422");
|
||||
const [currentSpriteHUD, setCurrentSpriteHUD] = useState<SpriteHudData>(
|
||||
(level_sprite_huds as SpriteHuds)[currentSprite.substr(2)]
|
||||
);
|
||||
const [spriteUpdateCooldown, setSpriteUpdateCooldown] = useState(false);
|
||||
|
||||
const [mainStarfieldVisible, setMainStarfieldVisible] = useState(false);
|
||||
|
||||
const [HUDActive, setHUDActive] = useState(1);
|
||||
|
||||
const { bigHUDPositionX } = useSpring({
|
||||
bigHUDPositionX: HUDActive,
|
||||
config: { duration: 500 },
|
||||
});
|
||||
|
||||
const { longHUDPositionX } = useSpring({
|
||||
longHUDPositionX: HUDActive,
|
||||
config: { duration: 500 },
|
||||
});
|
||||
|
||||
const { boringHUDPositionX } = useSpring({
|
||||
boringHUDPositionX: HUDActive,
|
||||
config: { duration: 500 },
|
||||
});
|
||||
|
||||
const bigHUDPosX = bigHUDPositionX.to(
|
||||
[0, 1],
|
||||
[
|
||||
currentSpriteHUD["big"]["initial_position"][0],
|
||||
currentSpriteHUD["big"]["position"][0],
|
||||
]
|
||||
);
|
||||
|
||||
const boringHUDPosX = boringHUDPositionX.to(
|
||||
[0, 1],
|
||||
[
|
||||
currentSpriteHUD["boring"]["initial_position"][0],
|
||||
currentSpriteHUD["boring"]["position"][0],
|
||||
]
|
||||
);
|
||||
|
||||
const longHUDPosX = longHUDPositionX.to(
|
||||
[0, 1],
|
||||
[
|
||||
currentSpriteHUD["long"]["initial_position"][0],
|
||||
currentSpriteHUD["long"]["position"][0],
|
||||
]
|
||||
);
|
||||
|
||||
const [{ cameraRotationY }, setCameraRotationY] = useSpring(
|
||||
() => ({
|
||||
cameraRotationY: 0,
|
||||
config: { precision: 0.0001, duration: 1600 },
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const [{ cameraPositionY }, setCameraPositionY] = useSpring(
|
||||
() => ({
|
||||
cameraPositionY: 0,
|
||||
config: { precision: 0.0001, duration: 1200 },
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const [{ lainPositionY }, setLainPositionY] = useSpring(
|
||||
() => ({
|
||||
lainPositionY: -0.06,
|
||||
config: { precision: 0.0001, duration: 1200 },
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const [{ starfieldPositionY }, setStarfieldPositionY] = useSpring(
|
||||
() => ({
|
||||
starfieldPositionY: -0.5,
|
||||
config: { precision: 0.0001, duration: 1200 },
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const moveCamera = useCallback(
|
||||
(val: number) =>
|
||||
void setTimeout(
|
||||
() =>
|
||||
setCameraPositionY(() => ({
|
||||
cameraPositionY: cameraPositionY.get() + val,
|
||||
})),
|
||||
1300
|
||||
),
|
||||
[cameraPositionY, setCameraPositionY]
|
||||
);
|
||||
|
||||
const moveStarfield = useCallback(
|
||||
(val: number) =>
|
||||
void setTimeout(
|
||||
() =>
|
||||
setStarfieldPositionY(() => ({
|
||||
starfieldPositionY: starfieldPositionY.get() + val,
|
||||
})),
|
||||
1300
|
||||
),
|
||||
[starfieldPositionY, setStarfieldPositionY]
|
||||
);
|
||||
|
||||
const moveLain = useCallback(
|
||||
(val: number) =>
|
||||
void setTimeout(
|
||||
() =>
|
||||
setLainPositionY(() => ({
|
||||
lainPositionY: lainPositionY.get() + val,
|
||||
})),
|
||||
1300
|
||||
),
|
||||
[setLainPositionY, lainPositionY]
|
||||
);
|
||||
|
||||
const rotateCamera = useCallback(
|
||||
(val: number) =>
|
||||
void setTimeout(
|
||||
() =>
|
||||
setCameraRotationY(() => ({
|
||||
cameraRotationY: cameraRotationY.get() + val,
|
||||
})),
|
||||
1100
|
||||
),
|
||||
[setCameraRotationY, cameraRotationY]
|
||||
);
|
||||
|
||||
const camRotY = cameraRotationY.to([0, 1], [0, Math.PI]);
|
||||
const camPosY = cameraPositionY.to([0, 1], [0, Math.PI]);
|
||||
const lainPosY = lainPositionY.to([0, 1], [0, Math.PI]);
|
||||
const starfieldPosY = starfieldPositionY.to([0, 1], [0, Math.PI]);
|
||||
|
||||
const getMove = (currentLoc: string, key: string): string => {
|
||||
return (level_sprite_directions as SpriteDirections)[currentLoc][key];
|
||||
};
|
||||
|
||||
const getKeyCodeAssociation = (keyCode: number): string => {
|
||||
return ({
|
||||
40: "down",
|
||||
37: "left",
|
||||
38: "up",
|
||||
39: "right",
|
||||
} as KeyCodeAssociations)[keyCode];
|
||||
};
|
||||
|
||||
const setAnimationState = useCallback(
|
||||
(key: string) => {
|
||||
switch (key) {
|
||||
case "down":
|
||||
moveCamera(0.6);
|
||||
moveStarfield(-0.6);
|
||||
moveLain(-0.6);
|
||||
setLainMoveState(<LainMoveDown />);
|
||||
break;
|
||||
case "left":
|
||||
rotateCamera(0.15);
|
||||
setLainMoveState(<LainMoveLeft />);
|
||||
break;
|
||||
case "up":
|
||||
moveCamera(-0.6);
|
||||
moveStarfield(0.6);
|
||||
moveLain(0.6);
|
||||
setLainMoveState(<LainMoveUp />);
|
||||
break;
|
||||
case "right":
|
||||
rotateCamera(-0.1);
|
||||
setLainMoveState(<LainMoveRight />);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// set moving to true to avoid player from overlapping animations and stuff
|
||||
// by waiting for the anim to finish
|
||||
setLainMoving(true);
|
||||
|
||||
// wait for the anim to finish, set lain to standing state, release the move lock
|
||||
setTimeout(() => {
|
||||
setLainMoving(false);
|
||||
setLainMoveState(<LainStanding />);
|
||||
}, (lain_animations as LainAnimations)[key]["duration"]);
|
||||
},
|
||||
[moveCamera, moveLain, rotateCamera, moveStarfield]
|
||||
);
|
||||
|
||||
const updateHUD = useCallback(() => {
|
||||
setHUDActive((prev: number) => Number(!prev));
|
||||
}, [setHUDActive]);
|
||||
|
||||
const moveDispatcher = useCallback(
|
||||
(move: string, key: string) => {
|
||||
console.log(move[0]);
|
||||
switch (move[0]) {
|
||||
// do nothing / cant move
|
||||
case undefined:
|
||||
break;
|
||||
// "+" in the json denotes that the sprite chosen by getMove is not currently on screen,
|
||||
// therefore lain should first do a move (up/down/left/right) and then that sprite
|
||||
// will be chosen.
|
||||
case "+":
|
||||
if (!spriteUpdateCooldown) {
|
||||
// hide the hud
|
||||
updateHUD();
|
||||
// disable glow on current sprite
|
||||
setCurrentSprite("");
|
||||
setSpriteUpdateCooldown(true);
|
||||
setAnimationState(key);
|
||||
setTimeout(() => {
|
||||
setOrthoCameraPosY(1.88);
|
||||
updateHUD();
|
||||
setCurrentSprite(move.substr(1));
|
||||
setCurrentSpriteHUD(
|
||||
(level_sprite_huds as SpriteHuds)[move.substr(3)]
|
||||
);
|
||||
}, (lain_animations as LainAnimations)[key]["duration"] + 200);
|
||||
setTimeout(() => {
|
||||
setSpriteUpdateCooldown(false);
|
||||
}, 1000);
|
||||
}
|
||||
break;
|
||||
// only change sprite focus
|
||||
default:
|
||||
if (!spriteUpdateCooldown) {
|
||||
setCurrentSprite(move);
|
||||
setSpriteUpdateCooldown(true);
|
||||
// toggle hud to go back in
|
||||
updateHUD();
|
||||
setTimeout(() => {
|
||||
// change hud while its hidden
|
||||
setCurrentSpriteHUD(
|
||||
(level_sprite_huds as SpriteHuds)[move.substr(2)]
|
||||
);
|
||||
// toggle it again to be shown in the new position
|
||||
updateHUD();
|
||||
}, 500);
|
||||
setTimeout(() => {
|
||||
setSpriteUpdateCooldown(false);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
[setAnimationState, updateHUD, spriteUpdateCooldown]
|
||||
);
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(event) => {
|
||||
const { keyCode } = event;
|
||||
|
||||
const key = getKeyCodeAssociation(keyCode);
|
||||
|
||||
if (key && !isLainMoving) {
|
||||
const move = getMove(currentSprite, key);
|
||||
|
||||
console.log(key);
|
||||
|
||||
moveDispatcher(move, key);
|
||||
}
|
||||
},
|
||||
[isLainMoving, currentSprite, moveDispatcher]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", handleKeyPress);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyPress);
|
||||
document.getElementsByTagName("body")[0].className = "";
|
||||
};
|
||||
}, [handleKeyPress]);
|
||||
|
||||
const groupRef = useRef<THREE.Object3D>();
|
||||
|
||||
useFrame(() => {
|
||||
if (isIntro) {
|
||||
if (groupRef.current) {
|
||||
if (groupRef.current!.rotation.x > 0) {
|
||||
if (groupRef.current!.position.z > -1) {
|
||||
groupRef.current!.rotation.x -= 0.015;
|
||||
} else {
|
||||
// if the position z is at a certain point speed up the rotation
|
||||
groupRef.current!.rotation.x -= 0.01;
|
||||
}
|
||||
}
|
||||
if (groupRef.current!.position.y > 0) {
|
||||
groupRef.current!.position.y -= 0.015;
|
||||
}
|
||||
|
||||
if (groupRef.current!.position.z < 0) {
|
||||
groupRef.current!.position.z += 0.04;
|
||||
}
|
||||
|
||||
// if the rotation hits this value that means that the intro is finished.
|
||||
// using a settimeout or something similar resulted in clunkiness, since it was dependant
|
||||
// on load times.
|
||||
if (
|
||||
parseFloat(groupRef.current!.rotation.x.toPrecision(2)) === -0.005
|
||||
) {
|
||||
setLainMoving(false);
|
||||
setLainMoveState(<LainStanding />);
|
||||
|
||||
setTimeout(() => {
|
||||
setIsIntro(false);
|
||||
document.getElementsByTagName("canvas")[0].className =
|
||||
"hub-background";
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// when pos z reaches this point, make the main starfield appear
|
||||
if (parseFloat(groupRef.current!.position.z.toPrecision(2)) === -1.4) {
|
||||
if (!mainStarfieldVisible) {
|
||||
setMainStarfieldVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// pos-z ? => 3
|
||||
// rot-x 1.5 => 0
|
||||
// grp rot/pos both 0,0,0 => ?
|
||||
return (
|
||||
<a.perspectiveCamera
|
||||
position-z={3}
|
||||
position-y={camPosY}
|
||||
rotation-y={camRotY}
|
||||
>
|
||||
<Suspense fallback={null}>
|
||||
<group rotation={[2.3, 0, 0]} position={[0, 1.5, -7.5]} ref={groupRef}>
|
||||
<Preloader />
|
||||
<Hub currentSprite={currentSprite} />
|
||||
<OrthoCamera
|
||||
longHUDPosX={longHUDPosX}
|
||||
bigHUDPosX={bigHUDPosX}
|
||||
boringHUDPosX={boringHUDPosX}
|
||||
longHUDPosYZ={[
|
||||
currentSpriteHUD!["long"]["position"][1],
|
||||
currentSpriteHUD!["long"]["position"][2],
|
||||
]}
|
||||
boringHUDPosYZ={[
|
||||
currentSpriteHUD!["boring"]["position"][1],
|
||||
currentSpriteHUD!["boring"]["position"][2],
|
||||
]}
|
||||
bigHUDPosYZ={[
|
||||
currentSpriteHUD!["big"]["position"][1],
|
||||
currentSpriteHUD!["big"]["position"][2],
|
||||
]}
|
||||
longHUDType={currentSpriteHUD!["long"]["type"]}
|
||||
boringHUDType={currentSpriteHUD!["boring"]["type"]}
|
||||
bigHUDType={currentSpriteHUD!["big"]["type"]}
|
||||
longHUDScale={
|
||||
currentSpriteHUD!["long"]["scale"] as [number, number, number]
|
||||
}
|
||||
boringHUDScale={
|
||||
currentSpriteHUD!["boring"]["scale"] as [number, number, number]
|
||||
}
|
||||
bigHUDScale={
|
||||
currentSpriteHUD!["big"]["scale"] as [number, number, number]
|
||||
}
|
||||
orthoCameraPosY={orthoCameraPosY}
|
||||
id={currentSprite}
|
||||
orbVisibility={!isIntro}
|
||||
hudVisibility={!isIntro}
|
||||
/>
|
||||
<Starfield
|
||||
starfieldPosY={starfieldPosY}
|
||||
mainStarfieldVisible={mainStarfieldVisible}
|
||||
introStarfieldVisible={isIntro}
|
||||
/>
|
||||
<Lights />
|
||||
<OrbitControls />
|
||||
</group>
|
||||
|
||||
<Lain
|
||||
isLainMoving={isLainMoving}
|
||||
lainMoveState={lainMoveState}
|
||||
lainPosY={lainPosY}
|
||||
/>
|
||||
</Suspense>
|
||||
</a.perspectiveCamera>
|
||||
);
|
||||
};
|
||||
export default Game;
|
8
src/components/HUD/CurrentHUDAtom.tsx
Normal file
8
src/components/HUD/CurrentHUDAtom.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import {atom} from "recoil";
|
||||
import level_sprite_huds from "../../resources/level_sprite_huds.json";
|
||||
import {SpriteHuds} from "./HUDElement";
|
||||
|
||||
export const currentHUDAtom = atom({
|
||||
key: "currentHUDAtom",
|
||||
default: (level_sprite_huds as SpriteHuds)["22"],
|
||||
});
|
6
src/components/HUD/HUDActiveAtom.tsx
Normal file
6
src/components/HUD/HUDActiveAtom.tsx
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { atom } from "recoil";
|
||||
|
||||
export const hudActiveAtom = atom({
|
||||
key: "hudActiveAtom",
|
||||
default: 1,
|
||||
});
|
163
src/components/HUD/HUDElement.tsx
Normal file
163
src/components/HUD/HUDElement.tsx
Normal file
|
@ -0,0 +1,163 @@
|
|||
import React, {memo} from "react";
|
||||
import {useLoader} from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import bigHud from "../../static/sprites/big_hud.png";
|
||||
import bigHudMirrored from "../../static/sprites/big_hud_mirrored.png";
|
||||
import longHud from "../../static/sprites/long_hud.png";
|
||||
import longHudMirrored from "../../static/sprites/long_hud_mirrored.png";
|
||||
import boringHud from "../../static/sprites/long_hud_boring.png";
|
||||
import boringHudMirrored from "../../static/sprites/long_hud_boring_mirrored.png";
|
||||
import {a, useSpring} from "@react-spring/three";
|
||||
import {useRecoilValue} from "recoil";
|
||||
import {hudActiveAtom} from "./HUDActiveAtom";
|
||||
import {currentHUDAtom} from "./CurrentHUDAtom";
|
||||
|
||||
export type HUDElementProps = {
|
||||
hudVisibility: boolean;
|
||||
};
|
||||
|
||||
type HudShapeData = {
|
||||
position: number[];
|
||||
scale: number[];
|
||||
type: string;
|
||||
initial_position: number[];
|
||||
};
|
||||
|
||||
export type SpriteHudData = {
|
||||
long: HudShapeData;
|
||||
boring: HudShapeData;
|
||||
big: HudShapeData;
|
||||
};
|
||||
|
||||
export type SpriteHuds = {
|
||||
[sprite_hud_id: string]: SpriteHudData;
|
||||
};
|
||||
|
||||
const HUDElement = memo((props: HUDElementProps) => {
|
||||
const currentSpriteHUD = useRecoilValue(currentHUDAtom);
|
||||
const hudActive = useRecoilValue(hudActiveAtom);
|
||||
|
||||
const { bigHUDPositionX } = useSpring({
|
||||
bigHUDPositionX: hudActive,
|
||||
config: { duration: 500 },
|
||||
});
|
||||
|
||||
const { longHUDPositionX } = useSpring({
|
||||
longHUDPositionX: hudActive,
|
||||
config: { duration: 500 },
|
||||
});
|
||||
|
||||
const { boringHUDPositionX } = useSpring({
|
||||
boringHUDPositionX: hudActive,
|
||||
config: { duration: 500 },
|
||||
});
|
||||
|
||||
const bigHUDPosX = bigHUDPositionX.to(
|
||||
[0, 1],
|
||||
[
|
||||
currentSpriteHUD["big"]["initial_position"][0],
|
||||
currentSpriteHUD["big"]["position"][0],
|
||||
]
|
||||
);
|
||||
|
||||
const boringHUDPosX = boringHUDPositionX.to(
|
||||
[0, 1],
|
||||
[
|
||||
currentSpriteHUD["boring"]["initial_position"][0],
|
||||
currentSpriteHUD["boring"]["position"][0],
|
||||
]
|
||||
);
|
||||
|
||||
const longHUDPosX = longHUDPositionX.to(
|
||||
[0, 1],
|
||||
[
|
||||
currentSpriteHUD["long"]["initial_position"][0],
|
||||
currentSpriteHUD["long"]["position"][0],
|
||||
]
|
||||
);
|
||||
|
||||
// these hud elements come in all shapes and forms, some of them are mirrored, rotated
|
||||
// you name it. this function allows me to specify whether i want a normal texture
|
||||
// for the sprite or the mirrored/rotated one.
|
||||
const spriteTypeToSprite = (spriteType: string, hudElement: string) => {
|
||||
switch (spriteType) {
|
||||
case "normal":
|
||||
switch (hudElement) {
|
||||
case "long":
|
||||
return longHud;
|
||||
case "boring":
|
||||
return boringHud;
|
||||
case "big":
|
||||
return bigHud;
|
||||
}
|
||||
break;
|
||||
case "mirrored":
|
||||
switch (hudElement) {
|
||||
case "big":
|
||||
return bigHudMirrored;
|
||||
case "long":
|
||||
return longHudMirrored;
|
||||
case "boring":
|
||||
return boringHudMirrored;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const longHudTexture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
spriteTypeToSprite(currentSpriteHUD["long"]["type"], "long")!
|
||||
);
|
||||
|
||||
const longHudBoringTexture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
spriteTypeToSprite(currentSpriteHUD["boring"]["type"], "boring")!
|
||||
);
|
||||
|
||||
const bigHudTexture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
spriteTypeToSprite(currentSpriteHUD["big"]["type"], "big")!
|
||||
);
|
||||
|
||||
return (
|
||||
<group visible={props.hudVisibility}>
|
||||
<a.sprite
|
||||
position-x={longHUDPosX}
|
||||
position-y={currentSpriteHUD["long"]["position"][1]}
|
||||
position-z={currentSpriteHUD["long"]["position"][2]}
|
||||
scale={currentSpriteHUD["long"]["scale"] as [number, number, number]}
|
||||
>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={longHudTexture}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.sprite>
|
||||
<a.sprite
|
||||
position-x={boringHUDPosX}
|
||||
position-y={currentSpriteHUD!["boring"]["position"][1]}
|
||||
position-z={currentSpriteHUD!["boring"]["position"][2]}
|
||||
scale={currentSpriteHUD!["boring"]["scale"] as [number, number, number]}
|
||||
>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={longHudBoringTexture}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.sprite>
|
||||
<a.sprite
|
||||
position-x={bigHUDPosX}
|
||||
position-y={currentSpriteHUD!["big"]["position"][1]}
|
||||
position-z={currentSpriteHUD!["big"]["position"][2]}
|
||||
scale={currentSpriteHUD!["big"]["scale"] as [number, number, number]}
|
||||
>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={bigHudTexture}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.sprite>
|
||||
</group>
|
||||
);
|
||||
});
|
||||
|
||||
export default HUDElement;
|
|
@ -1,117 +0,0 @@
|
|||
import React, { memo } from "react";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import bigHud from "../static/sprites/big_hud.png";
|
||||
import bigHudMirrored from "../static/sprites/big_hud_mirrored.png";
|
||||
import longHud from "../static/sprites/long_hud.png";
|
||||
import longHudMirrored from "../static/sprites/long_hud_mirrored.png";
|
||||
import boringHud from "../static/sprites/long_hud_boring.png";
|
||||
import boringHudMirrored from "../static/sprites/long_hud_boring_mirrored.png";
|
||||
import { a, Interpolation } from "@react-spring/three";
|
||||
|
||||
export type HUDElementProps = {
|
||||
longHUDType: string;
|
||||
boringHUDType: string;
|
||||
bigHUDType: string;
|
||||
|
||||
longHUDPosYZ: [number, number];
|
||||
longHUDPosX: Interpolation<number, number>;
|
||||
longHUDScale: [number, number, number];
|
||||
|
||||
boringHUDPosX: Interpolation<number, number>;
|
||||
boringHUDPosYZ: [number, number];
|
||||
boringHUDScale: [number, number, number];
|
||||
|
||||
bigHUDPosX: Interpolation<number, number>;
|
||||
bigHUDPosYZ: [number, number];
|
||||
bigHUDScale: [number, number, number];
|
||||
|
||||
hudVisibility: boolean;
|
||||
};
|
||||
|
||||
const HUDElement = memo((props: HUDElementProps) => {
|
||||
// these hud elements come in all shapes and forms, some of them are mirrored, rotated
|
||||
// you name it. this function allows me to specify whether i want a normal texture
|
||||
// for the sprite or the mirrored/rotated one.
|
||||
const spriteTypeToSprite = (spriteType: string, hudElement: string) => {
|
||||
switch (spriteType) {
|
||||
case "normal":
|
||||
switch (hudElement) {
|
||||
case "long":
|
||||
return longHud;
|
||||
case "boring":
|
||||
return boringHud;
|
||||
case "big":
|
||||
return bigHud;
|
||||
}
|
||||
break;
|
||||
case "mirrored":
|
||||
switch (hudElement) {
|
||||
case "big":
|
||||
return bigHudMirrored;
|
||||
case "long":
|
||||
return longHudMirrored;
|
||||
case "boring":
|
||||
return boringHudMirrored;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const longHudTexture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
spriteTypeToSprite(props.longHUDType, "long")!
|
||||
);
|
||||
|
||||
const longHudBoringTexture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
spriteTypeToSprite(props.boringHUDType, "boring")!
|
||||
);
|
||||
|
||||
const bigHudTexture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
spriteTypeToSprite(props.bigHUDType, "big")!
|
||||
);
|
||||
|
||||
return (
|
||||
<group visible={props.hudVisibility}>
|
||||
<a.sprite
|
||||
position-y={props.longHUDPosYZ[0]}
|
||||
position-z={props.longHUDPosYZ[1]}
|
||||
position-x={props.longHUDPosX}
|
||||
scale={props.longHUDScale}
|
||||
>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={longHudTexture}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.sprite>
|
||||
<a.sprite
|
||||
position-x={props.boringHUDPosX}
|
||||
position-y={props.boringHUDPosYZ[0]}
|
||||
position-z={props.boringHUDPosYZ[1]}
|
||||
scale={props.boringHUDScale}
|
||||
>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={longHudBoringTexture}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.sprite>
|
||||
<a.sprite
|
||||
position-x={props.bigHUDPosX}
|
||||
position-y={props.bigHUDPosYZ[0]}
|
||||
position-z={props.bigHUDPosYZ[1]}
|
||||
scale={props.bigHUDScale}
|
||||
>
|
||||
<spriteMaterial
|
||||
attach="material"
|
||||
map={bigHudTexture}
|
||||
transparent={true}
|
||||
/>
|
||||
</a.sprite>
|
||||
</group>
|
||||
);
|
||||
});
|
||||
|
||||
export default HUDElement;
|
227
src/components/InputHandler.tsx
Normal file
227
src/components/InputHandler.tsx
Normal file
|
@ -0,0 +1,227 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
LainMoveDown,
|
||||
LainMoveLeft,
|
||||
LainMoveRight,
|
||||
LainMoveUp,
|
||||
LainStanding,
|
||||
} from "./Lain/Lain";
|
||||
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||
import { hudActiveAtom } from "./HUD/HUDActiveAtom";
|
||||
import { currentSpriteAtom } from "./LevelSprite/CurrentSpriteAtom";
|
||||
import lain_animations from "../resources/lain_animations.json";
|
||||
import level_sprite_huds from "../resources/level_sprite_huds.json";
|
||||
import level_sprite_directions from "../resources/level_sprite_directions.json";
|
||||
import {
|
||||
lainMoveStateAtom,
|
||||
lainMovingAtom,
|
||||
lainPosYAtom,
|
||||
} from "./Lain/LainAtom";
|
||||
import { camPosYAtom, camRotYAtom } from "./MainScene/CameraAtom";
|
||||
import { starfieldPosYAtom } from "./Starfield/StarfieldAtom";
|
||||
import { currentHUDAtom } from "./HUD/CurrentHUDAtom";
|
||||
import { SpriteHuds } from "./HUD/HUDElement";
|
||||
|
||||
type KeyCodeAssociations = {
|
||||
[keyCode: number]: string;
|
||||
};
|
||||
|
||||
type SpriteDirectionData = {
|
||||
[direction: string]: string;
|
||||
};
|
||||
|
||||
type SpriteDirections = {
|
||||
[sprite_id: string]: SpriteDirectionData;
|
||||
};
|
||||
|
||||
type LainAnimationData = {
|
||||
frame_count: number;
|
||||
duration: number;
|
||||
};
|
||||
type LainAnimations = {
|
||||
[sprite: string]: LainAnimationData;
|
||||
};
|
||||
|
||||
const InputHandler = () => {
|
||||
const [currentSprite, setCurrentSprite] = useRecoilState(currentSpriteAtom);
|
||||
|
||||
const [lainMoving, setLainMoving] = useRecoilState(lainMovingAtom);
|
||||
const setLainMoveState = useSetRecoilState(lainMoveStateAtom);
|
||||
|
||||
const [spriteUpdateCooldown, setSpriteUpdateCooldown] = useState(false);
|
||||
|
||||
const setCurrentHUDElement = useSetRecoilState(currentHUDAtom);
|
||||
|
||||
const sethudActive = useSetRecoilState(hudActiveAtom);
|
||||
|
||||
const setCamPosY = useSetRecoilState(camPosYAtom);
|
||||
const setCamRotY = useSetRecoilState(camRotYAtom);
|
||||
|
||||
const setLainPosY = useSetRecoilState(lainPosYAtom);
|
||||
|
||||
const setStarfieldPosY = useSetRecoilState(starfieldPosYAtom);
|
||||
|
||||
const moveCamera = useCallback(
|
||||
(val: number) => {
|
||||
setCamPosY((prev: number) => prev + val);
|
||||
setLainPosY((prev: number) => prev - val);
|
||||
setStarfieldPosY((prev: number) => prev + val);
|
||||
},
|
||||
[setCamPosY, setLainPosY, setStarfieldPosY]
|
||||
);
|
||||
|
||||
const rotateCamera = useCallback(
|
||||
(val: number) => {
|
||||
setCamRotY((prev: number) => prev + val);
|
||||
},
|
||||
[setCamRotY]
|
||||
);
|
||||
|
||||
const getMove = (currentLoc: string, key: string): string => {
|
||||
return (level_sprite_directions as SpriteDirections)[currentLoc][key];
|
||||
};
|
||||
|
||||
const getKeyCodeAssociation = (keyCode: number): string => {
|
||||
return ({
|
||||
40: "down",
|
||||
37: "left",
|
||||
38: "up",
|
||||
39: "right",
|
||||
} as KeyCodeAssociations)[keyCode];
|
||||
};
|
||||
|
||||
const setAnimationState = useCallback(
|
||||
(key: string) => {
|
||||
switch (key) {
|
||||
case "down":
|
||||
setLainMoveState(<LainMoveDown />);
|
||||
setTimeout(() => {
|
||||
moveCamera(1.87);
|
||||
}, 1300);
|
||||
|
||||
break;
|
||||
case "left":
|
||||
rotateCamera(0.15);
|
||||
setLainMoveState(<LainMoveLeft />);
|
||||
break;
|
||||
case "up":
|
||||
setLainMoveState(<LainMoveUp />);
|
||||
setTimeout(() => {
|
||||
moveCamera(-1.87);
|
||||
}, 1300);
|
||||
break;
|
||||
case "right":
|
||||
rotateCamera(-0.1);
|
||||
setLainMoveState(<LainMoveRight />);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// set moving to true to avoid player from overlapping animations and stuff
|
||||
// by waiting for the anim to finish
|
||||
setLainMoving(true);
|
||||
|
||||
// wait for the anim to finish, set lain to standing state, release the move lock
|
||||
setTimeout(() => {
|
||||
setLainMoving(false);
|
||||
setLainMoveState(<LainStanding />);
|
||||
}, (lain_animations as LainAnimations)[key]["duration"]);
|
||||
},
|
||||
[moveCamera, rotateCamera, setLainMoveState]
|
||||
);
|
||||
|
||||
const updateHUD = useCallback(() => {
|
||||
sethudActive((prev: number) => Number(!prev));
|
||||
}, [sethudActive]);
|
||||
|
||||
const moveDispatcher = useCallback(
|
||||
(move: string, key: string) => {
|
||||
console.log(move[0]);
|
||||
switch (move[0]) {
|
||||
// do nothing / cant move
|
||||
case undefined:
|
||||
break;
|
||||
// "+" in the json denotes that the sprite chosen by getMove is not currently on screen,
|
||||
// therefore lain should first do a move (up/down/left/right) and then that sprite
|
||||
// will be chosen.
|
||||
case "+":
|
||||
if (!spriteUpdateCooldown) {
|
||||
// hide the hud
|
||||
updateHUD();
|
||||
// disable glow on current sprite
|
||||
setCurrentSprite("");
|
||||
setSpriteUpdateCooldown(true);
|
||||
setAnimationState(key);
|
||||
setTimeout(() => {
|
||||
updateHUD();
|
||||
// skip the "+"
|
||||
setCurrentSprite(move.substr(1));
|
||||
setCurrentHUDElement(
|
||||
(level_sprite_huds as SpriteHuds)[move.substr(3)]
|
||||
);
|
||||
}, (lain_animations as LainAnimations)[key]["duration"] + 200);
|
||||
setTimeout(() => {
|
||||
setSpriteUpdateCooldown(false);
|
||||
}, 1000);
|
||||
}
|
||||
break;
|
||||
// only change sprite focus
|
||||
default:
|
||||
if (!spriteUpdateCooldown) {
|
||||
setCurrentSprite(move);
|
||||
setSpriteUpdateCooldown(true);
|
||||
// toggle hud to go back in
|
||||
updateHUD();
|
||||
setTimeout(() => {
|
||||
// change hud while its hidden
|
||||
setCurrentHUDElement(
|
||||
(level_sprite_huds as SpriteHuds)[move.substr(2)]
|
||||
);
|
||||
// toggle it again to be shown in the new position
|
||||
updateHUD();
|
||||
}, 500);
|
||||
setTimeout(() => {
|
||||
setSpriteUpdateCooldown(false);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
setAnimationState,
|
||||
updateHUD,
|
||||
spriteUpdateCooldown,
|
||||
setCurrentHUDElement,
|
||||
setCurrentSprite,
|
||||
]
|
||||
);
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(event) => {
|
||||
const { keyCode } = event;
|
||||
|
||||
const key = getKeyCodeAssociation(keyCode);
|
||||
|
||||
if (key && !lainMoving) {
|
||||
const move = getMove(currentSprite, key);
|
||||
|
||||
console.log(key);
|
||||
|
||||
moveDispatcher(move, key);
|
||||
}
|
||||
},
|
||||
[lainMoving, currentSprite, moveDispatcher]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", handleKeyPress);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyPress);
|
||||
};
|
||||
}, [handleKeyPress]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export default InputHandler;
|
|
@ -1,20 +1,16 @@
|
|||
import { a, Interpolation } from "@react-spring/three";
|
||||
import { a, Interpolation, useSpring } from "@react-spring/three";
|
||||
import React, { Suspense, useState } from "react";
|
||||
import { useFrame, useLoader } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import { PlainSingularAnimator } from "three-plain-animator/lib/plain-singular-animator";
|
||||
import moveDownSpriteSheet from "../static/sprites/jump_down.png";
|
||||
import moveUpSpriteSheet from "../static/sprites/jump_up.png";
|
||||
import moveLeftSpriteSheet from "../static/sprites/move_left.png";
|
||||
import moveRightSpriteSheet from "../static/sprites/move_right.png";
|
||||
import standingSpriteSheet from "../static/sprites/standing.png";
|
||||
import introSpriteSheet from "../static/sprites/intro.png";
|
||||
|
||||
type LainProps = {
|
||||
isLainMoving: boolean;
|
||||
lainMoveState: JSX.Element;
|
||||
lainPosY: Interpolation<number, number>;
|
||||
};
|
||||
import moveDownSpriteSheet from "../../static/sprites/jump_down.png";
|
||||
import moveUpSpriteSheet from "../../static/sprites/jump_up.png";
|
||||
import moveLeftSpriteSheet from "../../static/sprites/move_left.png";
|
||||
import moveRightSpriteSheet from "../../static/sprites/move_right.png";
|
||||
import standingSpriteSheet from "../../static/sprites/standing.png";
|
||||
import introSpriteSheet from "../../static/sprites/intro.png";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { lainMoveStateAtom, lainMovingAtom, lainPosYAtom } from "./LainAtom";
|
||||
|
||||
type LainConstructorProps = {
|
||||
sprite: string;
|
||||
|
@ -23,7 +19,6 @@ type LainConstructorProps = {
|
|||
framesHorizontal: number;
|
||||
};
|
||||
|
||||
|
||||
const LainConstructor = (props: LainConstructorProps) => {
|
||||
// any here temporarily
|
||||
const lainSpriteTexture: any = useLoader(THREE.TextureLoader, props.sprite);
|
||||
|
@ -112,15 +107,24 @@ export const LainMoveUp = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const Lain = (props: LainProps) => {
|
||||
const Lain = () => {
|
||||
const lainMoving = useRecoilValue(lainMovingAtom);
|
||||
const lainMoveState = useRecoilValue(lainMoveStateAtom);
|
||||
const lainPosY = useRecoilValue(lainPosYAtom);
|
||||
|
||||
const lainPosYState = useSpring({
|
||||
lainPosY: lainPosY,
|
||||
config: { duration: 1200 },
|
||||
});
|
||||
|
||||
return (
|
||||
<Suspense fallback={<>loading...</>}>
|
||||
<a.sprite
|
||||
position-x={0.1}
|
||||
position-y={props.lainPosY}
|
||||
position-y={lainPosYState.lainPosY}
|
||||
scale={[4.9, 4.9, 4.9]}
|
||||
>
|
||||
{props.isLainMoving ? props.lainMoveState : <LainStanding />}
|
||||
{lainMoving ? lainMoveState : <LainStanding />}
|
||||
</a.sprite>
|
||||
</Suspense>
|
||||
);
|
17
src/components/Lain/LainAtom.tsx
Normal file
17
src/components/Lain/LainAtom.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { atom } from "recoil";
|
||||
import React from "react";
|
||||
|
||||
export const lainPosYAtom = atom({
|
||||
key: "lainPosYAtom",
|
||||
default: -0.15,
|
||||
});
|
||||
|
||||
export const lainMovingAtom = atom({
|
||||
key: "lainMovingAtom",
|
||||
default: false,
|
||||
});
|
||||
|
||||
export const lainMoveStateAtom = atom({
|
||||
key: "lainMoveStateAtom",
|
||||
default: <></>,
|
||||
});
|
6
src/components/LevelSprite/CurrentSpriteAtom.tsx
Normal file
6
src/components/LevelSprite/CurrentSpriteAtom.tsx
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { atom } from 'recoil'
|
||||
|
||||
export const currentSpriteAtom = atom({
|
||||
key: 'currentSpriteAtom',
|
||||
default: "0422"
|
||||
})
|
|
@ -1,14 +1,14 @@
|
|||
import React, { useRef, useMemo, memo } from "react";
|
||||
import { useFrame, useLoader } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import Cou from "../static/sprites/Cou.png";
|
||||
import CouActive from "../static/sprites/Cou_active.png";
|
||||
import Dc from "../static/sprites/Dc.png";
|
||||
import DcActive from "../static/sprites/Dc_active.png";
|
||||
import SSkn from "../static/sprites/SSkn.png";
|
||||
import SSKnActive from "../static/sprites/SSkn_active.png";
|
||||
import Tda from "../static/sprites/Tda.png";
|
||||
import TdaActive from "../static/sprites/Tda_active.png";
|
||||
import Cou from "../../static/sprites/Cou.png";
|
||||
import CouActive from "../../static/sprites/Cou_active.png";
|
||||
import Dc from "../../static/sprites/Dc.png";
|
||||
import DcActive from "../../static/sprites/Dc_active.png";
|
||||
import SSkn from "../../static/sprites/SSkn.png";
|
||||
import SSKnActive from "../../static/sprites/SSkn_active.png";
|
||||
import Tda from "../../static/sprites/Tda.png";
|
||||
import TdaActive from "../../static/sprites/Tda_active.png";
|
||||
|
||||
type LevelSpriteConstructorProps = {
|
||||
sprite: string;
|
12
src/components/MainScene/CameraAtom.tsx
Normal file
12
src/components/MainScene/CameraAtom.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { atom } from "recoil";
|
||||
|
||||
export const camPosYAtom = atom({
|
||||
key: "camPosYAtom",
|
||||
default: 0,
|
||||
});
|
||||
|
||||
export const camRotYAtom = atom({
|
||||
key: "camRotYAtom",
|
||||
default: 0,
|
||||
});
|
||||
|
102
src/components/MainScene/MainScene.tsx
Normal file
102
src/components/MainScene/MainScene.tsx
Normal file
|
@ -0,0 +1,102 @@
|
|||
import { a, useSpring } from "@react-spring/three";
|
||||
import { OrbitControls } from "drei";
|
||||
import React, { Suspense, useEffect, useRef, useState } from "react";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
import Hub from "../Hub";
|
||||
import Lain, { LainIntro, LainStanding } from "../Lain/Lain";
|
||||
import Lights from "../Lights";
|
||||
import OrthoCamera from "../OrthoCamera/OrthoCamera";
|
||||
import Preloader from "../Preloader";
|
||||
import Starfield from "../Starfield/Starfield";
|
||||
import * as THREE from "three";
|
||||
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { lainMoveStateAtom, lainMovingAtom } from "../Lain/LainAtom";
|
||||
import { camPosYAtom, camRotYAtom } from "./CameraAtom";
|
||||
import InputHandler from "../InputHandler";
|
||||
|
||||
const MainScene = () => {
|
||||
const setLainMoving = useSetRecoilState(lainMovingAtom);
|
||||
const setLainMoveState = useSetRecoilState(lainMoveStateAtom);
|
||||
|
||||
const [isIntro, setIsIntro] = useState(true);
|
||||
const [mainStarfieldVisible, setMainStarfieldVisible] = useState(false);
|
||||
|
||||
const camPosY = useRecoilValue(camPosYAtom);
|
||||
const camRotY = useRecoilValue(camRotYAtom);
|
||||
|
||||
const cameraState = useSpring({
|
||||
camPosY: camPosY,
|
||||
camRotY: camRotY,
|
||||
config: { duration: 1200 },
|
||||
});
|
||||
|
||||
const groupRef = useRef<THREE.Object3D>();
|
||||
|
||||
useFrame(() => {
|
||||
if (isIntro) {
|
||||
if (groupRef.current) {
|
||||
if (groupRef.current!.rotation.x > 0) {
|
||||
if (groupRef.current!.position.z > -1) {
|
||||
groupRef.current!.rotation.x -= 0.015;
|
||||
} else {
|
||||
// if the position z is at a certain point speed up the rotation
|
||||
groupRef.current!.rotation.x -= 0.01;
|
||||
}
|
||||
}
|
||||
if (groupRef.current!.position.y > 0) {
|
||||
groupRef.current!.position.y -= 0.015;
|
||||
}
|
||||
|
||||
if (groupRef.current!.position.z < 0) {
|
||||
groupRef.current!.position.z += 0.04;
|
||||
}
|
||||
|
||||
// if the rotation hits this value that means that the intro is finished.
|
||||
// using a settimeout or something similar resulted in clunkiness, since it was dependant
|
||||
// on load times.
|
||||
if (
|
||||
parseFloat(groupRef.current!.rotation.x.toPrecision(2)) === -0.005
|
||||
) {
|
||||
setLainMoving(false);
|
||||
setLainMoveState(<LainStanding />);
|
||||
|
||||
setTimeout(() => {
|
||||
setIsIntro(false);
|
||||
document.getElementsByTagName("canvas")[0].className =
|
||||
"hub-background";
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setLainMoving(true);
|
||||
setLainMoveState(<LainIntro />);
|
||||
}, [setLainMoveState, setLainMoving]);
|
||||
|
||||
return (
|
||||
<a.perspectiveCamera
|
||||
position-z={3}
|
||||
position-y={cameraState.camPosY}
|
||||
rotation-y={cameraState.camRotY}
|
||||
>
|
||||
<Suspense fallback={null}>
|
||||
<group rotation={[2.3, 0, 0]} position={[0, 1.5, -7.5]} ref={groupRef}>
|
||||
<InputHandler />
|
||||
<Preloader />
|
||||
<Hub />
|
||||
<OrthoCamera orbVisibility={!isIntro} hudVisibility={!isIntro} />
|
||||
<Starfield
|
||||
mainStarfieldVisible={mainStarfieldVisible}
|
||||
introStarfieldVisible={isIntro}
|
||||
/>
|
||||
<Lights />
|
||||
<OrbitControls />
|
||||
</group>
|
||||
<Lain />
|
||||
</Suspense>
|
||||
</a.perspectiveCamera>
|
||||
);
|
||||
};
|
||||
export default MainScene;
|
|
@ -1,53 +0,0 @@
|
|||
import React, { useMemo, useRef } from "react";
|
||||
import { useFrame, useThree } from "react-three-fiber";
|
||||
import { Scene } from "three";
|
||||
import HUDElement, { HUDElementProps } from "./HUDElement";
|
||||
import Orb from "./Orb";
|
||||
|
||||
interface OrthoCameraProps extends HUDElementProps {
|
||||
id: string;
|
||||
orthoCameraPosY: number;
|
||||
orbVisibility: boolean;
|
||||
}
|
||||
|
||||
const OrthoCamera = (props: OrthoCameraProps) => {
|
||||
const { gl, scene, camera } = useThree();
|
||||
const virtualScene = useMemo(() => new Scene(), []);
|
||||
const virtualCam = useRef();
|
||||
|
||||
useFrame(() => {
|
||||
gl.autoClear = false;
|
||||
gl.clear();
|
||||
gl.render(scene, camera);
|
||||
gl.clearDepth();
|
||||
gl.render(virtualScene, virtualCam.current!);
|
||||
}, 1);
|
||||
|
||||
//-0.6
|
||||
return (
|
||||
<orthographicCamera
|
||||
ref={virtualCam}
|
||||
position={[0, props.orthoCameraPosY, 10]}
|
||||
>
|
||||
<HUDElement
|
||||
longHUDType={props.longHUDType}
|
||||
boringHUDType={props.boringHUDType}
|
||||
bigHUDType={props.bigHUDType}
|
||||
longHUDPosYZ={props.longHUDPosYZ}
|
||||
longHUDPosX={props.longHUDPosX}
|
||||
longHUDScale={props.longHUDScale}
|
||||
boringHUDPosYZ={props.boringHUDPosYZ}
|
||||
boringHUDPosX={props.boringHUDPosX}
|
||||
boringHUDScale={props.boringHUDScale}
|
||||
bigHUDPosYZ={props.bigHUDPosYZ}
|
||||
bigHUDPosX={props.bigHUDPosX}
|
||||
bigHUDScale={props.bigHUDScale}
|
||||
key={props.id}
|
||||
hudVisibility={props.hudVisibility}
|
||||
/>
|
||||
<Orb orbVisibility={props.orbVisibility} />
|
||||
</orthographicCamera>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrthoCamera;
|
37
src/components/OrthoCamera/OrthoCamera.tsx
Normal file
37
src/components/OrthoCamera/OrthoCamera.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import React, {useMemo, useRef} from "react";
|
||||
import {useFrame, useThree} from "react-three-fiber";
|
||||
import {Scene} from "three";
|
||||
import HUDElement from "../HUD/HUDElement";
|
||||
import Orb from "../Orb";
|
||||
import {useRecoilValue} from "recoil";
|
||||
import {orthoCamPosYAtom} from "./OrthoCameraAtom";
|
||||
|
||||
interface OrthoCameraProps {
|
||||
orbVisibility: boolean;
|
||||
hudVisibility: boolean;
|
||||
}
|
||||
|
||||
const OrthoCamera = (props: OrthoCameraProps) => {
|
||||
const { gl, scene, camera } = useThree();
|
||||
const virtualScene = useMemo(() => new Scene(), []);
|
||||
const virtualCam = useRef();
|
||||
const orthoCameraPosY = useRecoilValue(orthoCamPosYAtom);
|
||||
|
||||
useFrame(() => {
|
||||
gl.autoClear = false;
|
||||
gl.clear();
|
||||
gl.render(scene, camera);
|
||||
gl.clearDepth();
|
||||
gl.render(virtualScene, virtualCam.current!);
|
||||
}, 1);
|
||||
|
||||
//-0.6
|
||||
return (
|
||||
<orthographicCamera ref={virtualCam} position={[0, orthoCameraPosY, 10]}>
|
||||
<HUDElement key={1} hudVisibility={props.hudVisibility} />
|
||||
<Orb orbVisibility={props.orbVisibility} />
|
||||
</orthographicCamera>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrthoCamera;
|
7
src/components/OrthoCamera/OrthoCameraAtom.tsx
Normal file
7
src/components/OrthoCamera/OrthoCameraAtom.tsx
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { atom } from "recoil";
|
||||
|
||||
export const orthoCamPosYAtom = atom({
|
||||
key: "orthoCamPosYAtom",
|
||||
default: 0,
|
||||
});
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { a, Interpolation } from "@react-spring/three";
|
||||
import React, { createRef, memo, RefObject, useMemo, useRef } from "react";
|
||||
import { a, Interpolation, useSpring } from "@react-spring/three";
|
||||
import React, {createRef, memo, RefObject, useEffect, useMemo, useRef} from "react";
|
||||
import { useFrame } from "react-three-fiber";
|
||||
import * as THREE from "three";
|
||||
import { starfieldPosYAtom } from "./StarfieldAtom";
|
||||
|
||||
type StarRefsAndIncrementors = [
|
||||
React.MutableRefObject<React.RefObject<THREE.Object3D>[]>,
|
||||
|
@ -9,7 +10,6 @@ type StarRefsAndIncrementors = [
|
|||
][];
|
||||
|
||||
type StarfieldProps = {
|
||||
starfieldPosY: Interpolation<number, number>;
|
||||
introStarfieldVisible: boolean;
|
||||
mainStarfieldVisible: boolean;
|
||||
};
|
||||
|
@ -35,6 +35,11 @@ type IntroStarfieldObjectData = {
|
|||
const Starfield = memo((props: StarfieldProps) => {
|
||||
const introStarfieldGroupRef = useRef<THREE.Object3D>();
|
||||
|
||||
const starfieldState = useSpring({
|
||||
starfieldPosY: starfieldPosYAtom,
|
||||
config: { duration: 1200 },
|
||||
});
|
||||
|
||||
const uniformConstructor = (col: string) => {
|
||||
return {
|
||||
color1: {
|
||||
|
@ -237,6 +242,10 @@ const Starfield = memo((props: StarfieldProps) => {
|
|||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
console.log('ssd')
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<a.group
|
||||
|
@ -273,7 +282,7 @@ const Starfield = memo((props: StarfieldProps) => {
|
|||
<a.group
|
||||
position={[-0.7, 0, -5]}
|
||||
rotation={[0, 0, 0]}
|
||||
position-y={props.starfieldPosY}
|
||||
position-y={starfieldPosYAtom}
|
||||
visible={props.mainStarfieldVisible}
|
||||
>
|
||||
{mainStarfieldObjects.map((obj: StarfieldObjectData) =>
|
7
src/components/Starfield/StarfieldAtom.tsx
Normal file
7
src/components/Starfield/StarfieldAtom.tsx
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { atom } from "recoil";
|
||||
|
||||
export const starfieldPosYAtom = atom({
|
||||
key: "starfieldPosYAtom",
|
||||
default: 0,
|
||||
});
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
import * as serviceWorker from "./serviceWorker";
|
||||
import { RecoilRoot } from "recoil";
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
|
|
Loading…
Reference in a new issue