mirror of
https://github.com/ad044/lainTSX.git
synced 2024-10-22 23:19:06 +00:00
added second ring, tweaked code, camera functions properly
This commit is contained in:
parent
25f60c8d13
commit
af26c3563c
9 changed files with 225 additions and 135 deletions
BIN
public/models/ring1.glb
Normal file
BIN
public/models/ring1.glb
Normal file
Binary file not shown.
|
@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||
import Intro from "./components/Intro";
|
||||
import Game from "./components/Game";
|
||||
import "./static/css/main.css";
|
||||
import "./static/css/hub.css";
|
||||
|
||||
const App = () => {
|
||||
const [moveToGame, setMoveToGame] = useState(false);
|
||||
|
|
|
@ -10,7 +10,8 @@ import Lain, {
|
|||
} from "./Lain";
|
||||
import Hub from "./Hub";
|
||||
//import Orb from "./Orb";
|
||||
import { OrbitControls } from "drei";
|
||||
import { OrbitControls, PerspectiveCamera } from "drei";
|
||||
import Lights from "./Lights";
|
||||
|
||||
type KeyCodeAssociations = {
|
||||
[keyCode: number]: string;
|
||||
|
@ -20,17 +21,34 @@ type FrameCounts = {
|
|||
[animation: string]: number;
|
||||
};
|
||||
|
||||
// value by which to rotate/move the ring on the y axis
|
||||
type LowerRingValues = {
|
||||
[direction: string]: number;
|
||||
};
|
||||
|
||||
const Game = () => {
|
||||
const [isLainMoving, setLainMoving] = useState(false);
|
||||
const [lainMoveState, setLainMoveState] = useState(<LainStanding />);
|
||||
const [lainPosY, setLainPosY] = useState(-0.2);
|
||||
|
||||
const [lowerRingRotationY, setLowerRingRotationY] = useState(5);
|
||||
const [lowerRingPositionY, setLowerRingPositionY] = useState(-0.31);
|
||||
const [cameraPosY, setCameraPosY] = useState(0);
|
||||
const [cameraRotationY, setCameraRotationY] = useState(0);
|
||||
|
||||
const moveCamera = (value: number, duration: number) => {
|
||||
const moveInterval = setInterval(() => {
|
||||
setCameraPosY((prev: number) => prev + value);
|
||||
setLainPosY((prev: number) => prev - value);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(moveInterval);
|
||||
}, duration);
|
||||
};
|
||||
|
||||
const rotateCamera = (value: number, duration: number) => {
|
||||
const rotationInterval = setInterval(() => {
|
||||
setCameraRotationY((prev: number) => prev + value);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(rotationInterval);
|
||||
}, duration);
|
||||
};
|
||||
|
||||
const getKeyValue = <U extends keyof T, T extends object>(key: U) => (
|
||||
obj: T
|
||||
|
@ -93,35 +111,6 @@ const Game = () => {
|
|||
}, getAnimationDuration(key));
|
||||
};
|
||||
|
||||
const getLowerRingValue = (direction: string) => {
|
||||
return getKeyValue<keyof LowerRingValues, LowerRingValues>(direction)({
|
||||
left: 0.002,
|
||||
right: -0.002,
|
||||
up: -0.005,
|
||||
down: 0.005,
|
||||
});
|
||||
};
|
||||
|
||||
const rotateLowerRing = (key: string, duration: number) => {
|
||||
const rotationInterval = setInterval(() => {
|
||||
setLowerRingRotationY((prev) => prev + getLowerRingValue(key));
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(rotationInterval);
|
||||
}, duration);
|
||||
};
|
||||
|
||||
const moveLowerRing = (key: string, duration: number) => {
|
||||
const moveInterval = setInterval(() => {
|
||||
setLowerRingPositionY((prev) => prev + getLowerRingValue(key));
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(moveInterval);
|
||||
}, duration);
|
||||
};
|
||||
|
||||
const handleUserKeyPress = useCallback(
|
||||
(event) => {
|
||||
const { _, keyCode } = event;
|
||||
|
@ -129,22 +118,33 @@ const Game = () => {
|
|||
const key = getKeyCodeAssociation(keyCode);
|
||||
|
||||
console.log(key);
|
||||
|
||||
if (!isLainMoving) {
|
||||
setAnimationState(key);
|
||||
setTimeout(() => {
|
||||
switch (key) {
|
||||
case "left":
|
||||
setTimeout(() => {
|
||||
rotateCamera(0.001, 1600);
|
||||
}, 1100);
|
||||
break;
|
||||
case "right":
|
||||
rotateLowerRing(key, 1000);
|
||||
setTimeout(() => {
|
||||
rotateCamera(-0.001, 1600);
|
||||
}, 1100);
|
||||
break;
|
||||
case "up":
|
||||
setTimeout(() => {
|
||||
moveCamera(-0.005, 1200);
|
||||
}, 1300);
|
||||
break;
|
||||
case "down":
|
||||
moveLowerRing(key, 1000);
|
||||
setTimeout(() => {
|
||||
moveCamera(0.005, 1200);
|
||||
}, 1300);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, 1200);
|
||||
}
|
||||
},
|
||||
[isLainMoving]
|
||||
|
@ -153,23 +153,31 @@ const Game = () => {
|
|||
useEffect(() => {
|
||||
window.addEventListener("keydown", handleUserKeyPress);
|
||||
|
||||
document.getElementsByTagName("canvas")[0].className = "hub-background";
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleUserKeyPress);
|
||||
document.getElementsByTagName("body")[0].className = "";
|
||||
};
|
||||
}, [handleUserKeyPress]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Canvas shadowMap concurrent camera={{ position: [0, -0.1, -2] }}>
|
||||
<Lain isLainMoving={isLainMoving} lainMoveState={lainMoveState} />
|
||||
<Hub
|
||||
lowerRingRotationY={lowerRingRotationY}
|
||||
lowerRingPositionY={lowerRingPositionY}
|
||||
{/* <Canvas camera={{ position: [0, 0, -2] }}> */}
|
||||
<Canvas>
|
||||
<PerspectiveCamera
|
||||
position={[0, cameraPosY, 3]}
|
||||
rotation={[0, cameraRotationY, 0]}
|
||||
>
|
||||
<OrbitControls />
|
||||
<Lain
|
||||
isLainMoving={isLainMoving}
|
||||
lainMoveState={lainMoveState}
|
||||
lainPosY={lainPosY}
|
||||
/>
|
||||
<ambientLight color={0x808080} />
|
||||
<pointLight color={0xffffff} position={[0, 0, 700]} intensity={0.5} />
|
||||
<pointLight color={0x7f7f7f} position={[0, 1000, 0]} intensity={1} />
|
||||
<pointLight color={0xffffff} position={[0, 0, 0]} intensity={0.1} />
|
||||
<Hub />
|
||||
<Lights />
|
||||
</PerspectiveCamera>
|
||||
</Canvas>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
import React, { Suspense } from "react";
|
||||
import Ring0 from "./Ring0";
|
||||
import Ring1 from "./Ring1";
|
||||
|
||||
type HubProps = {
|
||||
lowerRingPositionY: number;
|
||||
lowerRingRotationY: number;
|
||||
};
|
||||
|
||||
const Hub = (props: HubProps) => {
|
||||
const Hub = (props: any) => {
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<React.Fragment>loading...</React.Fragment>}>
|
||||
<Ring0
|
||||
lowerRingPositionY={props.lowerRingPositionY}
|
||||
lowerRingRotationY={props.lowerRingRotationY}
|
||||
/>
|
||||
<Suspense fallback={<>loading...</>}>
|
||||
<Ring1 />
|
||||
<Ring0 />
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as THREE from "three";
|
|||
import introSpriteSheet from "../static/sprites/intro.png";
|
||||
import moveDownSpriteSheet from "../static/sprites/jump_down.png";
|
||||
import standingSpriteSheet from "../static/sprites/standing.png";
|
||||
import moveLeftSpriteSheet from "../static/sprites/move_left1.png";
|
||||
import moveLeftSpriteSheet from "../static/sprites/move_left.png";
|
||||
import moveRightSpriteSheet from "../static/sprites/move_right.png";
|
||||
import moveUpSpriteSheet from "../static/sprites/jump_up.png";
|
||||
import { PlainSingularAnimator } from "three-plain-animator/lib/plain-singular-animator";
|
||||
|
@ -12,26 +12,26 @@ import { PlainSingularAnimator } from "three-plain-animator/lib/plain-singular-a
|
|||
type LainProps = {
|
||||
isLainMoving: boolean;
|
||||
lainMoveState: JSX.Element;
|
||||
lainPosY: number;
|
||||
};
|
||||
|
||||
type LainConstructorProps = {
|
||||
sprite: string;
|
||||
frameCount: number;
|
||||
framesVertical: number;
|
||||
framesHorizontal: number;
|
||||
};
|
||||
|
||||
const LainConstructor = (props: LainConstructorProps) => {
|
||||
// any here temporarily
|
||||
const spriteTexture: any = useLoader(
|
||||
THREE.TextureLoader,
|
||||
props.sprite
|
||||
);
|
||||
const spriteTexture: any = useLoader(THREE.TextureLoader, props.sprite);
|
||||
|
||||
const [animator] = useState(
|
||||
() =>
|
||||
new PlainSingularAnimator(
|
||||
spriteTexture,
|
||||
props.frameCount,
|
||||
1,
|
||||
props.framesHorizontal,
|
||||
props.framesVertical,
|
||||
props.frameCount,
|
||||
props.frameCount * 0.27
|
||||
)
|
||||
|
@ -42,57 +42,84 @@ const LainConstructor = (props: LainConstructorProps) => {
|
|||
});
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<sprite position={[0.1, -0.7, 0]} scale={[3.3, 3.3, 3.3]}>
|
||||
<spriteMaterial attach="material" map={spriteTexture}></spriteMaterial>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainIntro = () => {
|
||||
return (
|
||||
<LainConstructor
|
||||
sprite={standingSpriteSheet}
|
||||
frameCount={1}
|
||||
framesHorizontal={8}
|
||||
framesVertical={6}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainStanding = () => {
|
||||
return (
|
||||
<LainConstructor
|
||||
sprite={standingSpriteSheet}
|
||||
frameCount={3}
|
||||
framesHorizontal={3}
|
||||
framesVertical={1}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainMoveDown = () => {
|
||||
return (
|
||||
<LainConstructor
|
||||
sprite={moveDownSpriteSheet}
|
||||
frameCount={36}
|
||||
framesHorizontal={6}
|
||||
framesVertical={6}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainMoveLeft = () => {
|
||||
return (
|
||||
<LainConstructor
|
||||
sprite={moveLeftSpriteSheet}
|
||||
frameCount={47}
|
||||
framesVertical={6}
|
||||
framesHorizontal={8}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainMoveRight = () => {
|
||||
return (
|
||||
<LainConstructor
|
||||
sprite={moveRightSpriteSheet}
|
||||
frameCount={47}
|
||||
framesHorizontal={8}
|
||||
framesVertical={6}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainMoveUp = () => {
|
||||
return (
|
||||
<LainConstructor
|
||||
sprite={moveUpSpriteSheet}
|
||||
frameCount={36}
|
||||
framesHorizontal={6}
|
||||
framesVertical={6}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Lain = (props: LainProps) => {
|
||||
return (
|
||||
<Suspense fallback={<>loading...</>}>
|
||||
<sprite position={[0.1, props.lainPosY, 0]} scale={[4.3, 4.3, 4.3]}>
|
||||
{props.isLainMoving ? props.lainMoveState : <LainStanding />}
|
||||
</sprite>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
export const LainIntro = () => {
|
||||
return <LainConstructor sprite={introSpriteSheet} frameCount={51} />;
|
||||
};
|
||||
|
||||
export const LainStanding = () => {
|
||||
return <LainConstructor sprite={standingSpriteSheet} frameCount={1} />;
|
||||
};
|
||||
|
||||
export const LainMoveDown = () => {
|
||||
return <LainConstructor sprite={moveDownSpriteSheet} frameCount={36} />;
|
||||
};
|
||||
|
||||
export const LainMoveLeft = () => {
|
||||
return <LainConstructor sprite={moveLeftSpriteSheet} frameCount={47} />;
|
||||
};
|
||||
|
||||
export const LainMoveRight = () => {
|
||||
return <LainConstructor sprite={moveRightSpriteSheet} frameCount={47} />;
|
||||
};
|
||||
|
||||
export const LainMoveUp = () => {
|
||||
return <LainConstructor sprite={moveUpSpriteSheet} frameCount={36} />;
|
||||
};
|
||||
|
||||
const Lain = (props: LainProps) => {
|
||||
return (
|
||||
<>
|
||||
{/* without a suspense the sprites wont load, and the suspense loading
|
||||
animation takes about .3 seconds to finish for each sprite resulting in
|
||||
blinks between each spritesheet. with a nested suspense we can have
|
||||
LainStanding as the suspense fallback with a fallback of its own (the
|
||||
loading message) which will only be shown once, when the game loads. */}
|
||||
<Suspense
|
||||
fallback={
|
||||
<Suspense fallback={<React.Fragment>loading...</React.Fragment>}>
|
||||
<LainStanding />
|
||||
</Suspense>
|
||||
}
|
||||
>
|
||||
{props.isLainMoving ? props.lainMoveState : <LainStanding />}
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Lain;
|
||||
|
|
14
src/components/Lights.tsx
Normal file
14
src/components/Lights.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from "react";
|
||||
|
||||
const Lights = () => {
|
||||
return (
|
||||
<>
|
||||
<ambientLight color={0x808080} />
|
||||
<pointLight color={0xffffff} position={[0, 0, 700]} intensity={0.5} />
|
||||
<pointLight color={0x7f7f7f} position={[0, 1000, 0]} intensity={1} />
|
||||
<pointLight color={0xffffff} position={[0, 0, 0]} intensity={0.1} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Lights;
|
|
@ -24,7 +24,7 @@ type GLTFResult = GLTF & {
|
|||
materials: {};
|
||||
};
|
||||
|
||||
const Ring0 = (props: Ring0Props) => {
|
||||
const Ring0 = (props: any) => {
|
||||
const { nodes, materials } = useLoader<GLTFResult>(
|
||||
GLTFLoader,
|
||||
"/models/ring0.glb",
|
||||
|
@ -33,14 +33,14 @@ const Ring0 = (props: Ring0Props) => {
|
|||
return (
|
||||
<group
|
||||
scale={[1.3, 1.3, 1.3]}
|
||||
position={[0, props.lowerRingPositionY, 0]}
|
||||
rotation={[0, props.lowerRingRotationY, 0]}
|
||||
position={[0, -0.27, 0]}
|
||||
rotation={[0, 0.26, 0]}
|
||||
dispose={null}
|
||||
>
|
||||
<mesh geometry={nodes.Circle.geometry} rotation={[0, Math.PI / 4, 0]}>
|
||||
<meshLambertMaterial
|
||||
attach="material"
|
||||
transparent={true}
|
||||
color={0x636363}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</mesh>
|
||||
|
@ -48,4 +48,4 @@ const Ring0 = (props: Ring0Props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Ring0
|
||||
export default Ring0;
|
||||
|
|
49
src/components/Ring1.tsx
Normal file
49
src/components/Ring1.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import * as THREE from "three";
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import { useLoader } from "react-three-fiber";
|
||||
import { GLTFLoader, GLTF } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { draco } from "drei";
|
||||
|
||||
type GLTFResult = GLTF & {
|
||||
nodes: {
|
||||
Circle002: THREE.Mesh;
|
||||
};
|
||||
materials: {};
|
||||
};
|
||||
|
||||
const Ring1 = (props: JSX.IntrinsicElements["group"]) => {
|
||||
const [higherRingRotation, setHigherRingRotation] = useState(0);
|
||||
|
||||
const { nodes, materials } = useLoader<GLTFResult>(
|
||||
GLTFLoader,
|
||||
"/models/ring1.glb",
|
||||
draco("/draco-gltf/")
|
||||
);
|
||||
|
||||
const ring1PermaRotation = () => {
|
||||
setHigherRingRotation((prev) => prev + 0.002);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setInterval(ring1PermaRotation, 1);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<group
|
||||
position={[0, 0.4, 0]}
|
||||
rotation={[0, higherRingRotation, 0]}
|
||||
scale={[1.3, 1.3, 1.3]}
|
||||
dispose={null}
|
||||
>
|
||||
<mesh geometry={nodes.Circle002.geometry} rotation={[0, Math.PI / 4, 0]}>
|
||||
<meshLambertMaterial
|
||||
attach="material"
|
||||
color={0x8b6ff7}
|
||||
side={THREE.DoubleSide}
|
||||
/>
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default Ring1;
|
|
@ -1,3 +0,0 @@
|
|||
export const getKeyValue = <U extends keyof T, T extends object>(key: U) => (
|
||||
obj: T
|
||||
) => obj[key];
|
Loading…
Reference in a new issue