feat: initialize sunrise with 100-player shared rooms
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { MathUtils, PerspectiveCamera, type Vector3 } from 'three';
|
||||
import { SCENE } from '../constants/scene.ts';
|
||||
import { MOVEMENT } from '../constants/movement.ts';
|
||||
|
||||
export function createFpsCameraController(camera: PerspectiveCamera, canvas: HTMLCanvasElement,
|
||||
pickDestination: (x: number, y: number) => Vector3 | null) {
|
||||
let destination: Vector3 | null = null;
|
||||
let gesture: { id: number; startX: number; startY: number; x: number; y: number; dragged: boolean; canMove: boolean } | null = null;
|
||||
canvas.tabIndex = 0;
|
||||
const cancelGesture = () => {
|
||||
const id = gesture?.id;
|
||||
gesture = null;
|
||||
if (id !== undefined && canvas.hasPointerCapture(id)) canvas.releasePointerCapture(id);
|
||||
};
|
||||
const clear = () => { destination = null; cancelGesture(); };
|
||||
const down = (event: PointerEvent) => {
|
||||
if (!event.isPrimary || gesture || (event.button !== 0 && event.button !== 2)) return;
|
||||
event.preventDefault();
|
||||
canvas.focus({ preventScroll: true });
|
||||
gesture = { id: event.pointerId, startX: event.clientX, startY: event.clientY,
|
||||
x: event.clientX, y: event.clientY, dragged: false, canMove: event.pointerType !== 'mouse' || event.button === 2 };
|
||||
canvas.setPointerCapture(event.pointerId);
|
||||
};
|
||||
const move = (event: PointerEvent) => {
|
||||
if (!gesture || gesture.id !== event.pointerId) return;
|
||||
if (Math.hypot(event.clientX - gesture.startX, event.clientY - gesture.startY) > MOVEMENT.dragThreshold) gesture.dragged = true;
|
||||
if (gesture.dragged) {
|
||||
camera.rotation.reorder('YXZ');
|
||||
camera.rotation.y -= (event.clientX - gesture.x) * MOVEMENT.dragSensitivity;
|
||||
camera.rotation.x = MathUtils.clamp(camera.rotation.x - (event.clientY - gesture.y) * MOVEMENT.dragSensitivity,
|
||||
-MathUtils.degToRad(SCENE.pitchLimitDegrees), MathUtils.degToRad(SCENE.pitchLimitDegrees));
|
||||
}
|
||||
gesture.x = event.clientX;
|
||||
gesture.y = event.clientY;
|
||||
};
|
||||
const up = (event: PointerEvent) => {
|
||||
if (!gesture || gesture.id !== event.pointerId) return;
|
||||
const tap = !gesture.dragged && Math.hypot(event.clientX - gesture.startX, event.clientY - gesture.startY) <= MOVEMENT.dragThreshold;
|
||||
if (tap && gesture.canMove) destination = pickDestination(event.clientX, event.clientY);
|
||||
cancelGesture();
|
||||
};
|
||||
const cancel = (event: PointerEvent) => { if (gesture?.id === event.pointerId) cancelGesture(); };
|
||||
const contextMenu = (event: Event) => event.preventDefault();
|
||||
window.addEventListener('blur', clear);
|
||||
canvas.addEventListener('blur', clear);
|
||||
document.addEventListener('visibilitychange', clear);
|
||||
canvas.addEventListener('pointerdown', down);
|
||||
canvas.addEventListener('pointermove', move);
|
||||
canvas.addEventListener('pointerup', up);
|
||||
canvas.addEventListener('pointercancel', cancel);
|
||||
canvas.addEventListener('lostpointercapture', cancel);
|
||||
canvas.addEventListener('contextmenu', contextMenu);
|
||||
return {
|
||||
get destination() { return destination; },
|
||||
get looking() { return Boolean(gesture?.dragged); },
|
||||
stop() { destination = null; },
|
||||
active() { return document.activeElement === canvas; },
|
||||
clear,
|
||||
dispose() {
|
||||
clear();
|
||||
window.removeEventListener('blur', clear);
|
||||
canvas.removeEventListener('blur', clear);
|
||||
document.removeEventListener('visibilitychange', clear);
|
||||
canvas.removeEventListener('pointerdown', down);
|
||||
canvas.removeEventListener('pointermove', move);
|
||||
canvas.removeEventListener('pointerup', up);
|
||||
canvas.removeEventListener('pointercancel', cancel);
|
||||
canvas.removeEventListener('lostpointercapture', cancel);
|
||||
canvas.removeEventListener('contextmenu', contextMenu);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user