Remove player collision logic from runtime-three module

This commit is contained in:
2026-04-04 15:52:36 +02:00
parent 6db8b82ed7
commit 3fdbc002b6

View File

@@ -1,149 +0,0 @@
import type { Vec3 } from "../core/vector";
import type { RuntimeBoxCollider } from "./runtime-scene-build";
export interface FirstPersonPlayerShape {
radius: number;
height: number;
eyeHeight: number;
}
export interface ResolvedPlayerMotion {
feetPosition: Vec3;
grounded: boolean;
collidedAxes: {
x: boolean;
y: boolean;
z: boolean;
};
}
export const FIRST_PERSON_PLAYER_SHAPE: FirstPersonPlayerShape = {
radius: 0.3,
height: 1.8,
eyeHeight: 1.6
};
type Axis = "x" | "y" | "z";
interface RuntimeAabb {
min: Vec3;
max: Vec3;
}
function createPlayerAabb(feetPosition: Vec3, shape: FirstPersonPlayerShape): RuntimeAabb {
return {
min: {
x: feetPosition.x - shape.radius,
y: feetPosition.y,
z: feetPosition.z - shape.radius
},
max: {
x: feetPosition.x + shape.radius,
y: feetPosition.y + shape.height,
z: feetPosition.z + shape.radius
}
};
}
function rangesOverlap(minA: number, maxA: number, minB: number, maxB: number): boolean {
return minA < maxB && maxA > minB;
}
function resolveAxis(
axis: Axis,
nextFeetPosition: Vec3,
delta: number,
shape: FirstPersonPlayerShape,
colliders: RuntimeBoxCollider[]
): { collided: boolean; grounded: boolean } {
if (delta === 0) {
return {
collided: false,
grounded: false
};
}
nextFeetPosition[axis] += delta;
let collided = false;
let grounded = false;
for (const collider of colliders) {
const playerAabb = createPlayerAabb(nextFeetPosition, shape);
const overlapsOtherAxes =
axis === "x"
? rangesOverlap(playerAabb.min.y, playerAabb.max.y, collider.min.y, collider.max.y) &&
rangesOverlap(playerAabb.min.z, playerAabb.max.z, collider.min.z, collider.max.z)
: axis === "y"
? rangesOverlap(playerAabb.min.x, playerAabb.max.x, collider.min.x, collider.max.x) &&
rangesOverlap(playerAabb.min.z, playerAabb.max.z, collider.min.z, collider.max.z)
: rangesOverlap(playerAabb.min.x, playerAabb.max.x, collider.min.x, collider.max.x) &&
rangesOverlap(playerAabb.min.y, playerAabb.max.y, collider.min.y, collider.max.y);
if (!overlapsOtherAxes) {
continue;
}
switch (axis) {
case "x":
if (delta > 0 && playerAabb.max.x > collider.min.x && playerAabb.min.x < collider.min.x) {
nextFeetPosition.x = collider.min.x - shape.radius;
collided = true;
} else if (delta < 0 && playerAabb.min.x < collider.max.x && playerAabb.max.x > collider.max.x) {
nextFeetPosition.x = collider.max.x + shape.radius;
collided = true;
}
break;
case "y":
if (delta > 0 && playerAabb.max.y > collider.min.y && playerAabb.min.y < collider.min.y) {
nextFeetPosition.y = collider.min.y - shape.height;
collided = true;
} else if (delta < 0 && playerAabb.min.y < collider.max.y && playerAabb.max.y > collider.max.y) {
nextFeetPosition.y = collider.max.y;
collided = true;
grounded = true;
}
break;
case "z":
if (delta > 0 && playerAabb.max.z > collider.min.z && playerAabb.min.z < collider.min.z) {
nextFeetPosition.z = collider.min.z - shape.radius;
collided = true;
} else if (delta < 0 && playerAabb.min.z < collider.max.z && playerAabb.max.z > collider.max.z) {
nextFeetPosition.z = collider.max.z + shape.radius;
collided = true;
}
break;
}
}
return {
collided,
grounded
};
}
export function resolveFirstPersonMotion(
feetPosition: Vec3,
motion: Vec3,
shape: FirstPersonPlayerShape,
colliders: RuntimeBoxCollider[]
): ResolvedPlayerMotion {
const nextFeetPosition = {
...feetPosition
};
const xResolution = resolveAxis("x", nextFeetPosition, motion.x, shape, colliders);
const zResolution = resolveAxis("z", nextFeetPosition, motion.z, shape, colliders);
const yResolution = resolveAxis("y", nextFeetPosition, motion.y, shape, colliders);
return {
feetPosition: nextFeetPosition,
grounded: yResolution.grounded,
collidedAxes: {
x: xResolution.collided,
y: yResolution.collided,
z: zResolution.collided
}
};
}