diff --git a/workshop/steps/11-capstone/game.js b/workshop/steps/11-capstone/game.js index a520fd5..4c1ff5d 100644 --- a/workshop/steps/11-capstone/game.js +++ b/workshop/steps/11-capstone/game.js @@ -89,6 +89,7 @@ ctx.imageSmoothingEnabled = false; // player is an AABB (top-left corner + size) const player = { x: 40, y: 40, w: 12, h: 12 }; +window.player = player; // walls: a border plus a few interior blocks to slide against const T = 8; // border thickness @@ -101,7 +102,7 @@ const walls = [ { x: 0, y: H - T, w: W, h: T }, // bottom { x: 0, y: 0, w: T, h: H }, // left { x: W - T, y: 0, w: T, h: H }, // right - { x: 150, y: 30, w: 16, h: 90 }, // a pillar + { x: 144, y: 30, w: 12, h: 82 }, // a pillar { x: 96, y: 96, w: 60, h: 16 }, // a bar ledge, ]; @@ -160,23 +161,56 @@ function penetrationVector(a, b) { return null; } -/** - * moveAndSlide, but immune to the overlap trap: first push `box` out of any - * wall it is already inside (plus an EPSILON of slack, same idea as the - * backoff in the loop), THEN run the normal sweep loop from the safe spot. - * - * Everything you need is penetrationVector above and given.ts. - */ -function safeMoveAndSlide(box, v, walls) { - for (const wall of walls) { - const pv = penetrationVector(box, wall); +function resolveOverlaps(box, walls) { + const res = { + x: box.x, + y: box.y, + settled: true, + }; + + const count = walls.length; + let index = 0; + let tries = 0; + + while (index < count) { + const pv = penetrationVector(box, walls[index++]); + if (pv) { - box.x += pv.x > 0 ? pv.x + EPSILON : pv.x - EPSILON; - box.y += pv.y > 0 ? pv.y + EPSILON : pv.y - EPSILON; + if (pv.x !== 0) { + box.x += pv.x > 0 ? pv.x + EPSILON : pv.x - EPSILON; + } + if (pv.y !== 0) { + box.y += pv.y > 0 ? pv.y + EPSILON : pv.y - EPSILON; + } + + res.x = box.x; + res.y = box.y; + res.settled = false; + + index = 0; + tries += 1; + } else { + res.settled = true; + } + + if (tries > 7) { + break; } } - return moveAndSlide(box, v, walls); + return res; +} + +function safeMoveAndSlide(box, v, walls) { + const res = resolveOverlaps(box, walls); + if (res.settled) { + return moveAndSlide(box, v, walls); + } + + return { + x: box.x, + y: box.y, + }; } let then = performance.now();