Merge e_bike + gps into develop #7
@@ -3,13 +3,27 @@ import * as THREE from "three";
|
|||||||
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
|
import { InteractableObject } from "@/components/three/interaction/InteractableObject";
|
||||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
||||||
|
import { useDebugFolder } from "@/hooks/debug/useDebugFolder";
|
||||||
import { animateCameraTransition } from "@/world/GameCinematics";
|
import { animateCameraTransition } from "@/world/GameCinematics";
|
||||||
import { useGameStore } from "@/managers/stores/useGameStore";
|
import { useGameStore } from "@/managers/stores/useGameStore";
|
||||||
import type { Vector3Tuple } from "@/types/three/three";
|
import type { Vector3Tuple } from "@/types/three/three";
|
||||||
|
|
||||||
const EBIKE_MODEL_PATH = "/models/ebike/model.gltf";
|
const EBIKE_MODEL_PATH = "/models/ebike/model.gltf";
|
||||||
const EBIKE_CAMERA_POSITION: Vector3Tuple = [0, 1.5, -2];
|
|
||||||
const EBIKE_DROP_PLAYER_POSITION: Vector3Tuple = [2, 0, 0];
|
interface CameraTransform {
|
||||||
|
position: Vector3Tuple;
|
||||||
|
rotation: Vector3Tuple;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EBIKE_CAMERA_TRANSFORM: CameraTransform = {
|
||||||
|
position: [-3, 8, 0],
|
||||||
|
rotation: [0, 90, 0],
|
||||||
|
};
|
||||||
|
|
||||||
|
const EBIKE_DROP_PLAYER_TRANSFORM: CameraTransform = {
|
||||||
|
position: [3, 1.5, 0],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
};
|
||||||
|
|
||||||
interface EbikeProps {
|
interface EbikeProps {
|
||||||
position: Vector3Tuple;
|
position: Vector3Tuple;
|
||||||
@@ -19,17 +33,38 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element {
|
|||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { scene } = useLoggedGLTF(EBIKE_MODEL_PATH, {
|
const { scene } = useLoggedGLTF(EBIKE_MODEL_PATH, {
|
||||||
scope: "Ebike",
|
scope: "Ebike",
|
||||||
position,
|
position: [0, 0, 0],
|
||||||
});
|
});
|
||||||
const model = useClonedObject(scene);
|
const model = useClonedObject(scene);
|
||||||
const movementMode = useGameStore((state) => state.player.movementMode);
|
const movementMode = useGameStore((state) => state.player.movementMode);
|
||||||
|
|
||||||
|
const debugRef = useRef({ showCameraPoints: true });
|
||||||
|
useDebugFolder("Ebike", (folder) => {
|
||||||
|
folder
|
||||||
|
.add(debugRef.current, "showCameraPoints")
|
||||||
|
.name("Show Camera Points")
|
||||||
|
.onChange((value: boolean) => {
|
||||||
|
debugRef.current.showCameraPoints = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const camPointPos: Vector3Tuple = [
|
||||||
|
position[0] + EBIKE_CAMERA_TRANSFORM.position[0],
|
||||||
|
position[1] + EBIKE_CAMERA_TRANSFORM.position[1],
|
||||||
|
position[2] + EBIKE_CAMERA_TRANSFORM.position[2],
|
||||||
|
];
|
||||||
|
const dropPointPos: Vector3Tuple = [
|
||||||
|
position[0] + EBIKE_DROP_PLAYER_TRANSFORM.position[0],
|
||||||
|
position[1] + EBIKE_DROP_PLAYER_TRANSFORM.position[1],
|
||||||
|
position[2] + EBIKE_DROP_PLAYER_TRANSFORM.position[2],
|
||||||
|
];
|
||||||
|
|
||||||
const handleInteract = (): void => {
|
const handleInteract = (): void => {
|
||||||
if (movementMode === "walk") {
|
if (movementMode === "walk") {
|
||||||
const targetCamPos: Vector3Tuple = [
|
const targetCamPos: Vector3Tuple = [
|
||||||
position[0] + EBIKE_CAMERA_POSITION[0],
|
position[0] + EBIKE_CAMERA_TRANSFORM.position[0],
|
||||||
position[1] + EBIKE_CAMERA_POSITION[1],
|
position[1] + EBIKE_CAMERA_TRANSFORM.position[1],
|
||||||
position[2] + EBIKE_CAMERA_POSITION[2],
|
position[2] + EBIKE_CAMERA_TRANSFORM.position[2],
|
||||||
];
|
];
|
||||||
const targetLookAt: Vector3Tuple = [
|
const targetLookAt: Vector3Tuple = [
|
||||||
position[0],
|
position[0],
|
||||||
@@ -42,9 +77,9 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const targetCamPos: Vector3Tuple = [
|
const targetCamPos: Vector3Tuple = [
|
||||||
position[0] + EBIKE_DROP_PLAYER_POSITION[0],
|
position[0] + EBIKE_DROP_PLAYER_TRANSFORM.position[0],
|
||||||
position[1] + EBIKE_DROP_PLAYER_POSITION[1],
|
position[1] + EBIKE_DROP_PLAYER_TRANSFORM.position[1],
|
||||||
position[2] + EBIKE_DROP_PLAYER_POSITION[2],
|
position[2] + EBIKE_DROP_PLAYER_TRANSFORM.position[2],
|
||||||
];
|
];
|
||||||
const targetLookAt: Vector3Tuple = [
|
const targetLookAt: Vector3Tuple = [
|
||||||
position[0],
|
position[0],
|
||||||
@@ -59,7 +94,7 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group ref={groupRef}>
|
<group ref={groupRef} position={position}>
|
||||||
<primitive object={model} />
|
<primitive object={model} />
|
||||||
<InteractableObject
|
<InteractableObject
|
||||||
kind="trigger"
|
kind="trigger"
|
||||||
@@ -75,6 +110,26 @@ export function Ebike({ position }: EbikeProps): React.JSX.Element {
|
|||||||
<meshStandardMaterial color="red" opacity={0.5} transparent />
|
<meshStandardMaterial color="red" opacity={0.5} transparent />
|
||||||
</mesh>
|
</mesh>
|
||||||
</InteractableObject>
|
</InteractableObject>
|
||||||
|
{debugRef.current.showCameraPoints && (
|
||||||
|
<>
|
||||||
|
<mesh position={camPointPos}>
|
||||||
|
<sphereGeometry args={[0.3, 16, 16]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color="yellow"
|
||||||
|
emissive="yellow"
|
||||||
|
emissiveIntensity={0.5}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
<mesh position={dropPointPos}>
|
||||||
|
<sphereGeometry args={[0.3, 16, 16]} />
|
||||||
|
<meshStandardMaterial
|
||||||
|
color="cyan"
|
||||||
|
emissive="cyan"
|
||||||
|
emissiveIntensity={0.5}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ function playCinematic(
|
|||||||
let cameraTransitionTimeline: gsap.core.Timeline | null = null;
|
let cameraTransitionTimeline: gsap.core.Timeline | null = null;
|
||||||
let globalCamera: THREE.Camera | null = null;
|
let globalCamera: THREE.Camera | null = null;
|
||||||
|
|
||||||
export function setGlobalCamera(camera: THREE.Camera): void {
|
export function setGlobalCamera(camera: THREE.Camera | null): void {
|
||||||
globalCamera = camera;
|
globalCamera = camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,14 +51,12 @@ function StageAnchor({
|
|||||||
|
|
||||||
export function GameStageContent(): React.JSX.Element {
|
export function GameStageContent(): React.JSX.Element {
|
||||||
const mainState = useGameStore((state) => state.mainState);
|
const mainState = useGameStore((state) => state.mainState);
|
||||||
const isBikeUnlocked = useGameStore((state) => state.intro.isBikeUnlocked);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{mainState === "intro" ? (
|
{mainState === "intro" ? (
|
||||||
<StageAnchor color="#7dd3fc" position={[0, 4, 0]} />
|
<StageAnchor color="#7dd3fc" position={[0, 4, 0]} />
|
||||||
) : null}
|
) : null}
|
||||||
{/* {isBikeUnlocked ? <Ebike position={[0, 15, 0]} /> : null} */}
|
|
||||||
<Ebike position={[0, 5, 0]} />
|
<Ebike position={[0, 5, 0]} />
|
||||||
{GAME_REPAIR_ZONES.map((zone) => (
|
{GAME_REPAIR_ZONES.map((zone) => (
|
||||||
<RepairGame
|
<RepairGame
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
import { PointerLockControls } from "@react-three/drei";
|
import { PointerLockControls } from "@react-three/drei";
|
||||||
|
import { setGlobalCamera } from "@/world/GameCinematics";
|
||||||
|
|
||||||
export function PlayerCamera(): React.JSX.Element {
|
export function PlayerCamera(): React.JSX.Element {
|
||||||
|
const camera = useThree((state) => state.camera);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setGlobalCamera(camera);
|
||||||
return () => {
|
return () => {
|
||||||
|
setGlobalCamera(null);
|
||||||
document.exitPointerLock();
|
document.exitPointerLock();
|
||||||
};
|
};
|
||||||
}, []);
|
}, [camera]);
|
||||||
|
|
||||||
return <PointerLockControls />;
|
return <PointerLockControls />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export function PlayerController({
|
|||||||
const initializedRef = useRef(false);
|
const initializedRef = useRef(false);
|
||||||
const canMove = useGameStore((state) => state.missionFlow.canMove);
|
const canMove = useGameStore((state) => state.missionFlow.canMove);
|
||||||
const currentSpeed = useGameStore((state) => state.player.currentSpeed);
|
const currentSpeed = useGameStore((state) => state.player.currentSpeed);
|
||||||
|
const movementMode = useGameStore((state) => state.player.movementMode);
|
||||||
|
|
||||||
const capsule = useRef(createSpawnCapsule(spawnPosition));
|
const capsule = useRef(createSpawnCapsule(spawnPosition));
|
||||||
|
|
||||||
@@ -282,7 +283,9 @@ export function PlayerController({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (movementMode !== "ebike") {
|
||||||
camera.position.copy(capsule.current.end);
|
camera.position.copy(capsule.current.end);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user