Add animation triggers code

master
Ian Mancini 4 years ago
parent b6aa28f220
commit 94bc4d114b

@ -23,7 +23,7 @@ const Phantom: React.FC<PhantomProps> = ({ id }) => {
state.position[1] + 0.25, state.position[1] + 0.25,
state.position[2], state.position[2],
]) ])
ref.current?.rotation.fromArray(state.rotation) ref.current?.quaternion.fromArray(state.rotation)
}, },
(state) => state?.userTransforms?.[id], (state) => state?.userTransforms?.[id],
) )

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

@ -0,0 +1,42 @@
import { MathUtils, Quaternion, Vector3 } from 'three'
export const multiplyQuaternionVector3 = (rotation: Quaternion, point: Vector3) => {
const num1 = rotation.x * 2
const num2 = rotation.y * 2
const num3 = rotation.z * 2
const num4 = rotation.x * num1
const num5 = rotation.y * num2
const num6 = rotation.z * num3
const num7 = rotation.x * num2
const num8 = rotation.x * num3
const num9 = rotation.y * num3
const num10 = rotation.w * num1
const num11 = rotation.w * num2
const num12 = rotation.w * num3
const v = new Vector3()
v.x =
(1.0 - (num5 + num6)) * point.x + (num7 - num12) * point.y + (num8 + num11) * point.z
v.y =
(num7 + num12) * point.x + (1.0 - (num4 + num6)) * point.y + (num9 - num10) * point.z
v.z =
(num8 - num11) * point.x + (num9 + num10) * point.y + (1.0 - (num4 + num5)) * point.z
return v
}
export const repeat = (t: number, length: number): number => {
return t - Math.floor(t / length) * length
}
export const deltaAngle = (current: number, target: number): number => {
let num = repeat(target - current, 360)
if (num > 180) num -= 360
return num
}
export const relativeAngle = (axis: Vector3, q1: Quaternion, q2: Quaternion): number => {
const vecA = multiplyQuaternionVector3(q1, axis)
const vecB = multiplyQuaternionVector3(q2, axis)
const angleA = MathUtils.radToDeg(Math.atan2(vecA.x, vecA.z))
const angleB = MathUtils.radToDeg(Math.atan2(vecB.x, vecB.z))
return deltaAngle(angleA, angleB)
}
Loading…
Cancel
Save