WIP
This commit is contained in:
@@ -6,14 +6,15 @@ give you the skeleton — you write the code.
|
||||
|
||||
## The idea
|
||||
|
||||
A single collision doesn't end the frame (step 08's "leftover that matters"). You
|
||||
hit a wall at `t = 0.3`, slide, and **70% of the frame is still owed** — during
|
||||
which you might hit *another* wall, slide again, and so on. So moving is a small
|
||||
**loop**: sweep → stop at the nearest hit → slide → repeat with the leftover time.
|
||||
A single collision doesn't end the frame (step 08's "leftover that matters").
|
||||
You hit a wall at `t = 0.3`, slide, and **70% of the frame is still owed** —
|
||||
during which you might hit _another_ wall, slide again, and so on. So moving is
|
||||
a small **loop**: sweep → stop at the nearest hit → slide → repeat with the
|
||||
leftover time.
|
||||
|
||||
We loop a **maximum of 4 times** (your engine's cap) — enough to handle a corner
|
||||
(hit a wall, slide, hit the perpendicular wall, slide, stop) without ever risking
|
||||
an infinite loop.
|
||||
(hit a wall, slide, hit the perpendicular wall, slide, stop) without ever
|
||||
risking an infinite loop.
|
||||
|
||||
## The algorithm
|
||||
|
||||
@@ -46,29 +47,32 @@ return pos
|
||||
|
||||
Two things worth understanding, not just copying:
|
||||
|
||||
- **`move = vel * timeLeft`.** `vel` is a *full-frame* displacement (how far you'd
|
||||
go in a whole frame at this velocity). You only have `timeLeft` of the frame
|
||||
left, so the actual travel is `vel * timeLeft`. `sweptAABB`'s returned `time` is
|
||||
then a fraction *of that sub-move*, which is why `pos + move * time` is correct.
|
||||
- **`move = vel * timeLeft`.** `vel` is a _full-frame_ displacement (how far
|
||||
you'd go in a whole frame at this velocity). You only have `timeLeft` of the
|
||||
frame left, so the actual travel is `vel * timeLeft`. `sweptAABB`'s returned
|
||||
`time` is then a fraction _of that sub-move_, which is why `pos + move * time`
|
||||
is correct.
|
||||
|
||||
- **The `EPSILON` backoff** (`max(0, hit.time - EPSILON)`). Stop a hair *short* of
|
||||
the wall. If you land exactly on it, floating-point error can leave you a sliver
|
||||
inside — and next iteration's sweep would start already-overlapping, reporting a
|
||||
garbage negative-time "collision" that makes you stick or jitter. That tiny gap
|
||||
is exactly the `Math.max(0, time - EPSILON)` in your real `moveAndSlide`. Now you
|
||||
know *why* it's there. `EPSILON` is provided in `given.ts`.
|
||||
- **The `EPSILON` backoff** (`max(0, hit.time - EPSILON)`). Stop a hair _short_
|
||||
of the wall. If you land exactly on it, floating-point error can leave you a
|
||||
sliver inside — and next iteration's sweep would start already-overlapping,
|
||||
reporting a garbage negative-time "collision" that makes you stick or jitter.
|
||||
That tiny gap is exactly the `Math.max(0, time - EPSILON)` in your real
|
||||
`moveAndSlide`. Now you know _why_ it's there. `EPSILON` is provided in
|
||||
`given.ts`.
|
||||
|
||||
> **Moving-vs-moving (why your real engine has `velocity - otherVel`).** Here the
|
||||
> walls are static, so we sweep with plain `vel`. When the *other* body also moves,
|
||||
> you sweep in its frame of reference by using the **relative** velocity
|
||||
> `vel - otherVel` — then the exact same loop works, because from the other body's
|
||||
> point of view it's standing still. That's the only difference between this kata
|
||||
> and the full engine. The loop itself doesn't change.
|
||||
> **Moving-vs-moving (why your real engine has `velocity - otherVel`).** Here
|
||||
> the walls are static, so we sweep with plain `vel`. When the _other_ body also
|
||||
> moves, you sweep in its frame of reference by using the **relative** velocity
|
||||
> `vel - otherVel` — then the exact same loop works, because from the other
|
||||
> body's point of view it's standing still. That's the only difference between
|
||||
> this kata and the full engine. The loop itself doesn't change.
|
||||
|
||||
## Task
|
||||
|
||||
Implement `moveAndSlide(box, v, walls)` in `moveAndSlide.ts`. Everything you need —
|
||||
`sweptAABB`, `slide`, the vector ops, `EPSILON` — is finished in `given.ts`.
|
||||
Implement `moveAndSlide(box, v, walls)` in `moveAndSlide.ts`. Everything you
|
||||
need — `sweptAABB`, `slide`, the vector ops, `EPSILON` — is finished in
|
||||
`given.ts`.
|
||||
|
||||
```sh
|
||||
bun test workshop/steps/10-move-and-slide
|
||||
|
||||
Reference in New Issue
Block a user