pages235/src/cameraRotationControls.ts

95 lines
2.9 KiB
TypeScript

import { contro } from './controls'
import { activeModalStack, isGameActive, miscUiState, showModal } from './globalState'
import { options } from './optionsStorage'
import { hideNotification, notificationProxy } from './react/NotificationProvider'
import { pointerLock } from './utils'
import worldInteractions from './worldInteractions'
import { updateMotion, initMotionTracking } from './react/uiMotion'
let lastMouseMove: number
const MOTION_DAMPING = 0.92
const MAX_MOTION_OFFSET = 30
const motionVelocity = { x: 0, y: 0 }
const lastUpdate = performance.now()
export const updateCursor = () => {
worldInteractions.update()
}
export type CameraMoveEvent = {
movementX: number
movementY: number
type: string
stopPropagation?: () => void
}
export function onCameraMove (e: MouseEvent | CameraMoveEvent) {
if (!isGameActive(true)) return
if (e.type === 'mousemove' && !document.pointerLockElement) return
e.stopPropagation?.()
const now = performance.now()
// todo: limit camera movement for now to avoid unexpected jumps
if (now - lastMouseMove < 4) return
lastMouseMove = now
let { mouseSensX, mouseSensY } = options
if (mouseSensY === -1) mouseSensY = mouseSensX
moveCameraRawHandler({
x: e.movementX * mouseSensX * 0.0001,
y: e.movementY * mouseSensY * 0.0001
})
updateCursor()
updateMotion()
}
export const moveCameraRawHandler = ({ x, y }: { x: number; y: number }) => {
const maxPitch = 0.5 * Math.PI
const minPitch = -0.5 * Math.PI
viewer.world.lastCamUpdate = Date.now()
if (viewer.world.freeFlyMode) {
// Update freeFlyState directly
viewer.world.freeFlyState.yaw = (viewer.world.freeFlyState.yaw - x) % (2 * Math.PI)
viewer.world.freeFlyState.pitch = Math.max(minPitch, Math.min(maxPitch, viewer.world.freeFlyState.pitch - y))
return
}
if (!bot?.entity) return
const pitch = bot.entity.pitch - y
void bot.look(bot.entity.yaw - x, Math.max(minPitch, Math.min(maxPitch, pitch)), true)
}
window.addEventListener('mousemove', (e: MouseEvent) => {
onCameraMove(e)
}, { capture: true })
export const onControInit = () => {
contro.on('stickMovement', ({ stick, vector }) => {
if (!isGameActive(true)) return
if (stick !== 'right') return
let { x, z } = vector
if (Math.abs(x) < 0.18) x = 0
if (Math.abs(z) < 0.18) z = 0
onCameraMove({
movementX: x * 10,
movementY: z * 10,
type: 'stickMovement',
stopPropagation () {}
} as CameraMoveEvent)
miscUiState.usingGamepadInput = true
})
}
function pointerLockChangeCallback () {
if (notificationProxy.id === 'pointerlockchange') {
hideNotification()
}
if (viewer.renderer.xr.isPresenting) return // todo
if (!pointerLock.hasPointerLock && activeModalStack.length === 0 && miscUiState.gameLoaded) {
showModal({ reactType: 'pause-screen' })
}
}
document.addEventListener('pointerlockchange', pointerLockChangeCallback, false)