import { type AABB, type Span, sweepInterval, type Vec } from "./given.ts"; /** A collision: the fraction of the frame at impact, and the surface normal. */ export type Hit = { time: number; normal: Vec }; /** * A point at `p` moving by `v` over this frame, against a static box. * Returns the entry Hit, or null if there is no collision this frame. * * Reuse sweepInterval twice (x and y), then combine: * entry = max of the two entries, exit = min of the two exits. */ export function rayVsAABB(p: Vec, v: Vec, box: AABB): Hit | null { const spanX = sweepInterval(p.x, v.x, box.x, box.x + box.w); if (spanX === null) { return null; } const spanY = sweepInterval(p.y, v.y, box.y, box.y + box.h); if (spanY === null) { return null; } const span: Span = { entry: Math.max(spanX.entry, spanY.entry), exit: Math.min(spanX.exit, spanY.exit), }; if (span.entry > span.exit) { return null; } if (span.entry >= 1 || span.exit <= 0) { return null; } const time = span.entry; const normal = { x: 0, y: 0, }; if (spanX.entry > spanY.entry) { normal.x = v.x > 0 ? -1 : 1; } else { normal.y = v.y > 0 ? -1 : 1; } return { time, normal, }; }