|
|
|
@ -10,10 +10,12 @@ import {
|
|
|
|
|
Mesh,
|
|
|
|
|
CircleGeometry,
|
|
|
|
|
} from 'three'
|
|
|
|
|
import { relativeAngle } from './lib/math'
|
|
|
|
|
import WorldCollisions from './models/WorldCollisions'
|
|
|
|
|
|
|
|
|
|
import useStore from '../store'
|
|
|
|
|
import { MeshBasicMaterial } from 'three/src/materials/MeshBasicMaterial'
|
|
|
|
|
import { Quaternion } from 'three/src/math/Quaternion'
|
|
|
|
|
|
|
|
|
|
const SPEED = 1
|
|
|
|
|
const HEIGHT = 1.5
|
|
|
|
@ -22,10 +24,10 @@ const CIRCLE_SEGMENTS = 8
|
|
|
|
|
const InitialPosition = new Vector3(49.92, 3.15, 34.52)
|
|
|
|
|
|
|
|
|
|
const keys: Record<string, string> = {
|
|
|
|
|
KeyW: 'forward',
|
|
|
|
|
KeyS: 'backward',
|
|
|
|
|
KeyA: 'left',
|
|
|
|
|
KeyD: 'right',
|
|
|
|
|
KeyW: 'left',
|
|
|
|
|
KeyS: 'right',
|
|
|
|
|
KeyA: 'backward',
|
|
|
|
|
KeyD: 'forward',
|
|
|
|
|
ArrowUp: 'forward',
|
|
|
|
|
ArrowDown: 'backward',
|
|
|
|
|
ArrowLeft: 'left',
|
|
|
|
@ -35,6 +37,20 @@ const keys: Record<string, string> = {
|
|
|
|
|
}
|
|
|
|
|
const moveFieldByKey = (key: string) => keys[key]
|
|
|
|
|
|
|
|
|
|
const animations: Record<string, number> = {
|
|
|
|
|
idle: 0,
|
|
|
|
|
turn_right: 1,
|
|
|
|
|
turn_left: 2,
|
|
|
|
|
walk_backwards: 3,
|
|
|
|
|
walk: 4,
|
|
|
|
|
walk_right: 5,
|
|
|
|
|
walk_left: 6,
|
|
|
|
|
run: 7,
|
|
|
|
|
run_right: 8,
|
|
|
|
|
run_left: 9,
|
|
|
|
|
jump: 10,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function FirstPersonCamera(props: JSX.IntrinsicElements['perspectiveCamera']) {
|
|
|
|
|
const ref = useRef<PerspectiveCamera>()
|
|
|
|
|
const { setDefaultCamera } = useThree()
|
|
|
|
@ -73,6 +89,9 @@ const usePlayerControls = () => {
|
|
|
|
|
return movement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// define an axis, usually just up
|
|
|
|
|
const upVector = new Vector3(0, 1, 0)
|
|
|
|
|
|
|
|
|
|
// TODO Improve physics in player
|
|
|
|
|
const Player = () => {
|
|
|
|
|
const socket = useStore((state) => state.socket)
|
|
|
|
@ -84,8 +103,10 @@ const Player = () => {
|
|
|
|
|
const collisionsRef = useRef<Mesh<CircleGeometry, MeshBasicMaterial>>(null)
|
|
|
|
|
const velocity = useRef<Vector3>(new Vector3())
|
|
|
|
|
const direction = useRef<Vector3>(new Vector3())
|
|
|
|
|
const worldOrigin = useRef<Vector3>(new Vector3())
|
|
|
|
|
const currentPositionClone = useRef<Vector3>(new Vector3())
|
|
|
|
|
const pCameraQuaternion = useRef<Quaternion>(new Quaternion())
|
|
|
|
|
const worldOrigin = useRef<Vector3>(new Vector3())
|
|
|
|
|
const speed = useRef<number>(SPEED)
|
|
|
|
|
|
|
|
|
|
const bottomRaycaster = useRef(
|
|
|
|
|
new Raycaster(new Vector3(), new Vector3(0, -1, 0), 0, HEIGHT + 0.5),
|
|
|
|
@ -113,22 +134,53 @@ const Player = () => {
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const socketEmitTransformInterval = setInterval(() => {
|
|
|
|
|
if (socket && groupRef.current && camera) {
|
|
|
|
|
const cameraRotation = camera.rotation.toArray()
|
|
|
|
|
const cameraRotation = camera.quaternion.toArray()
|
|
|
|
|
const [x, , z] = direction.current.toArray()
|
|
|
|
|
|
|
|
|
|
let anim = animations.idle
|
|
|
|
|
|
|
|
|
|
if (x === 0 && z === 0) {
|
|
|
|
|
const rotationAngle = relativeAngle(
|
|
|
|
|
upVector,
|
|
|
|
|
camera.quaternion,
|
|
|
|
|
pCameraQuaternion.current,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (Math.abs(rotationAngle) > 10) {
|
|
|
|
|
anim =
|
|
|
|
|
rotationAngle > 1 ? animations.turn_right : (anim = animations.turn_left)
|
|
|
|
|
} else {
|
|
|
|
|
anim = animations.idle
|
|
|
|
|
}
|
|
|
|
|
} else if (x < 0) {
|
|
|
|
|
anim = animations.walk_backwards
|
|
|
|
|
} else if (x > 0 && z === 0) {
|
|
|
|
|
anim = speed.current > SPEED ? animations.run : animations.walk
|
|
|
|
|
} else if (x >= 0 && z > 0) {
|
|
|
|
|
anim = speed.current > SPEED ? animations.run_right : animations.walk_right
|
|
|
|
|
} else if (x >= 0 && z < 0) {
|
|
|
|
|
anim = speed.current > SPEED ? animations.run_left : animations.walk_left
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the signed difference in these angles
|
|
|
|
|
socket.emit('transform', {
|
|
|
|
|
position: [
|
|
|
|
|
groupRef.current?.position.x,
|
|
|
|
|
groupRef.current?.position.y,
|
|
|
|
|
groupRef.current?.position.z,
|
|
|
|
|
],
|
|
|
|
|
rotation: [cameraRotation[0], cameraRotation[1], cameraRotation[2]],
|
|
|
|
|
rotation: [...cameraRotation],
|
|
|
|
|
a: anim,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
pCameraQuaternion.current.copy(camera.quaternion)
|
|
|
|
|
}
|
|
|
|
|
}, 50)
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
clearInterval(socketEmitTransformInterval)
|
|
|
|
|
}
|
|
|
|
|
}, [])
|
|
|
|
|
}, [socket, groupRef.current, camera])
|
|
|
|
|
|
|
|
|
|
const moveForward = (distance: number) => {
|
|
|
|
|
if (groupRef.current) {
|
|
|
|
@ -175,12 +227,13 @@ const Player = () => {
|
|
|
|
|
direction.current.normalize()
|
|
|
|
|
|
|
|
|
|
// Running
|
|
|
|
|
const speed = run ? 1.5 : 1
|
|
|
|
|
speed.current = run && direction.current.x >= 0 ? 1.5 : 1
|
|
|
|
|
|
|
|
|
|
// Move
|
|
|
|
|
if (forward || backward)
|
|
|
|
|
velocity.current.z -= direction.current.z * SPEED * delta * speed
|
|
|
|
|
if (left || right) velocity.current.x -= direction.current.x * SPEED * delta * speed
|
|
|
|
|
velocity.current.z -= direction.current.z * SPEED * delta * speed.current
|
|
|
|
|
if (left || right)
|
|
|
|
|
velocity.current.x -= direction.current.x * SPEED * delta * speed.current
|
|
|
|
|
|
|
|
|
|
// Wall collisions
|
|
|
|
|
const collisionCircleGeometry = collisionCircle.current.geometry as Geometry
|
|
|
|
@ -213,8 +266,8 @@ const Player = () => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply speed
|
|
|
|
|
moveForward(-velocity.current.x * speed)
|
|
|
|
|
moveRight(-velocity.current.z * speed)
|
|
|
|
|
moveForward(-velocity.current.x * speed.current)
|
|
|
|
|
moveRight(-velocity.current.z * speed.current)
|
|
|
|
|
groupRef.current.position.y += velocity.current.y * delta
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -224,8 +277,8 @@ const Player = () => {
|
|
|
|
|
})
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<group ref={groupRef} position={InitialPosition} rotation={[0, -Math.PI / 2, 0]}>
|
|
|
|
|
<FirstPersonCamera rotation={[0, Math.PI / 2, 0]} />
|
|
|
|
|
<group ref={groupRef} position={InitialPosition}>
|
|
|
|
|
<FirstPersonCamera />
|
|
|
|
|
<mesh
|
|
|
|
|
ref={collisionCircle}
|
|
|
|
|
position={[0, -HEIGHT / 2, 0]}
|
|
|
|
|