60 lines
1.2 KiB
TypeScript
60 lines
1.2 KiB
TypeScript
import {
|
|
type AABB,
|
|
add,
|
|
EPSILON,
|
|
type Hit,
|
|
scale,
|
|
slide,
|
|
sweptAABB,
|
|
type Vec,
|
|
} from "./given.ts";
|
|
|
|
/**
|
|
* Move `box` by the full-frame displacement `v`, sliding along any `walls` it
|
|
* hits, up to 4 iterations. Returns the final corner position.
|
|
*
|
|
* See the README for the algorithm. You already have everything you need in
|
|
* given.ts: sweptAABB, slide, add, scale, EPSILON.
|
|
*/
|
|
export function moveAndSlide(box: AABB, v: Vec, walls: AABB[]): Vec {
|
|
let pos: Vec = { x: box.x, y: box.y };
|
|
let vel: Vec = { x: v.x, y: v.y };
|
|
|
|
let timeLeft = 1;
|
|
let i = 0;
|
|
while (i++ < 4 && timeLeft > 0) {
|
|
const move = scale(vel, timeLeft);
|
|
let nearest: Hit = {
|
|
normal: { x: 0, y: 0 },
|
|
time: 2,
|
|
};
|
|
|
|
for (const wall of walls) {
|
|
const hit = sweptAABB(
|
|
{
|
|
x: pos.x,
|
|
y: pos.y,
|
|
w: box.w,
|
|
h: box.h,
|
|
},
|
|
move,
|
|
wall,
|
|
);
|
|
if (hit !== null) {
|
|
nearest = hit.time < nearest.time ? hit : nearest;
|
|
}
|
|
}
|
|
|
|
if (nearest.time === 2) {
|
|
pos = add(pos, move);
|
|
break;
|
|
} else {
|
|
pos = add(pos, scale(move, Math.max(0, nearest.time - EPSILON)));
|
|
vel = slide(vel, nearest.normal);
|
|
timeLeft = timeLeft * (1 - nearest.time);
|
|
}
|
|
}
|
|
|
|
return pos;
|
|
}
|