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 } }