45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
import type { KinematicCharacterController } from "@dimforge/rapier3d-compat";
|
|
import { PLAYER_GROUND_MIN_NORMAL_Y } from "./playerJump";
|
|
|
|
export const PLAYER_GRAVITY = -18;
|
|
export const PLAYER_CHARACTER_CONTROLLER_OFFSET = 0.02;
|
|
export const PLAYER_STEP_HEIGHT = 0.55;
|
|
export const PLAYER_STEP_MIN_WIDTH = 0.15;
|
|
export const PLAYER_GROUND_SNAP_DISTANCE = PLAYER_STEP_HEIGHT;
|
|
export const PLAYER_GROUND_STICK_VELOCITY = -0.5;
|
|
export const PLAYER_MAX_FRAME_DELTA_SECONDS = 0.05;
|
|
export const PLAYER_TERMINAL_FALL_VELOCITY = -32;
|
|
|
|
/**
|
|
* Configures Rapier's kinematic controller for MMO-style traversal. Ordinary
|
|
* stairs and curb-sized seams are walkable, while taller obstacles remain
|
|
* blocking geometry and still require a real jump or another route.
|
|
*/
|
|
export function configurePlayerCharacterController(
|
|
controller: KinematicCharacterController,
|
|
): KinematicCharacterController {
|
|
controller.setUp({ x: 0, y: 1, z: 0 });
|
|
controller.setSlideEnabled(true);
|
|
controller.enableAutostep(PLAYER_STEP_HEIGHT, PLAYER_STEP_MIN_WIDTH, false);
|
|
controller.enableSnapToGround(PLAYER_GROUND_SNAP_DISTANCE);
|
|
controller.setMaxSlopeClimbAngle(Math.acos(PLAYER_GROUND_MIN_NORMAL_Y));
|
|
return controller;
|
|
}
|
|
|
|
export function playerFrameDeltaSeconds(deltaSeconds: number): number {
|
|
if (!Number.isFinite(deltaSeconds) || deltaSeconds <= 0) return 0;
|
|
return Math.min(deltaSeconds, PLAYER_MAX_FRAME_DELTA_SECONDS);
|
|
}
|
|
|
|
export function airbornePlayerVerticalVelocity(
|
|
currentVelocity: number,
|
|
deltaSeconds: number,
|
|
): number {
|
|
const velocity = Number.isFinite(currentVelocity) ? currentVelocity : 0;
|
|
const delta = playerFrameDeltaSeconds(deltaSeconds);
|
|
return Math.max(
|
|
PLAYER_TERMINAL_FALL_VELOCITY,
|
|
velocity + PLAYER_GRAVITY * delta,
|
|
);
|
|
}
|