meat/engine/world/CollisionWorld.ts

62 lines
1.6 KiB
TypeScript

import type { Vec3 } from "../math/Vec3"
import { Collider, type Collider as ColliderShape } from "./Collider"
import type { Terrain } from "./Terrain"
export type CollisionWorld = {
terrain: Terrain
staticColliders: ColliderShape[]
dynamicColliders: ColliderShape[]
}
export namespace CollisionWorld {
export function create(
terrain: Terrain,
staticColliders: ColliderShape[],
): CollisionWorld {
return { terrain, staticColliders, dynamicColliders: [] }
}
export function pushOut(
world: CollisionWorld,
position: Vec3,
radius: number,
): void {
pushFrom(world.staticColliders, position, radius)
pushFrom(world.dynamicColliders, position, radius)
}
export function groundHeight(world: CollisionWorld, position: Vec3): number {
let ground = world.terrain.heightAt(position.x, position.z)
ground = standingHeight(world.staticColliders, position, ground)
return standingHeight(world.dynamicColliders, position, ground)
}
function pushFrom(
colliders: ColliderShape[],
position: Vec3,
radius: number,
): void {
for (const collider of colliders) {
if (position.y < collider.top - 0.01) {
Collider.pushOut(collider, position, radius)
}
}
}
function standingHeight(
colliders: ColliderShape[],
position: Vec3,
initial: number,
): number {
let ground = initial
for (const collider of colliders) {
if (
collider.standable &&
Collider.contains(collider, position.x, position.z)
) {
ground = Math.max(ground, collider.top)
}
}
return ground
}
}