collision

This commit is contained in:
“chrisshank” 2024-12-06 23:08:36 -08:00
parent f5bad0b176
commit b40ba06404
2 changed files with 49 additions and 19 deletions

View File

@ -22,31 +22,55 @@
folk-shape {
border: 2px solid black;
}
p {
border: 1px solid grey;
max-width: 30ch;
margin: 0;
}
</style>
</head>
<body>
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
<folk-shape x="200" y="200" width="50" height="50"></folk-shape>
<folk-shape x="200" y="275" width="50" height="50"></folk-shape>
<folk-shape x="200" y="150" width="50" height="50"></folk-shape>
<folk-shape x="200" y="100" width="50" height="50"></folk-shape>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<folk-shape x="400" y="100" width="50" height="50"></folk-shape>
<folk-shape x="400" y="150" width="50" height="50"></folk-shape>
<folk-shape x="400" y="200" width="50" height="50"></folk-shape>
<folk-shape x="400" y="275" width="50" height="50"></folk-shape>
<script type="module">
import '../src/standalone/folk-shape.ts';
import { FolkShape } from '../src/standalone/folk-shape.ts';
import { aabbHitDetection } from '../src/common/collision.ts';
const shapes = Array.from(document.querySelectorAll('folk-shape'));
const getBoundingBox = (el) => (el instanceof FolkShape ? el.getTransformDOMRect() : el.getBoundingClientRect());
function handleCollision(e) {
for (const shape of shapes) {
if (shape === e.target) continue;
const hit = aabbHitDetection(shape.getTransformDOMRect(), e.target.getTransformDOMRect());
const hit = aabbHitDetection(getBoundingBox(shape), getBoundingBox(e.target));
if (hit === null) continue;
shape.x -= hit.delta.x;
shape.y -= hit.delta.y;
if (shape instanceof FolkShape) {
if (hit.delta.x !== 0) shape.x -= hit.delta.x;
if (hit.delta.y !== 0) shape.y -= hit.delta.y;
} else {
if (hit.delta.x !== 0) e.preventX();
if (hit.delta.y !== 0) e.preventY();
}
}
}

View File

@ -14,16 +14,22 @@ export class Hit {
normal: Point = { x: 0, y: 0 };
}
/** Test collisions of axis-aligned bounding boxes. */
export function aabbHitDetection(rect1: DOMRect, rect2: DOMRect, proximity = 0): Hit | null {
const dx = rect2.x - rect1.x;
const px = rect2.width / 2 + rect1.width / 2 - Math.abs(dx);
const center = (rect: DOMRectReadOnly) => ({
x: rect.x + rect.width / 2,
y: rect.y + rect.height / 2,
});
/** Test collisions of axis-aligned bounding boxes. */
export function aabbHitDetection(rect1: DOMRectReadOnly, rect2: DOMRectReadOnly): Hit | null {
const center1 = center(rect1);
const center2 = center(rect2);
const dx = center1.x - center2.x;
const px = (rect2.width + rect1.width) / 2 - Math.abs(dx);
if (px <= 0) return null;
const dy = rect2.y - rect1.y;
const py = rect2.height / 2 + rect1.height / 2 - Math.abs(dy);
const dy = center2.y - center1.y;
const py = (rect2.height + rect1.height) / 2 - Math.abs(dy);
if (py <= 0) return null;
const hit = new Hit();
@ -32,14 +38,14 @@ export function aabbHitDetection(rect1: DOMRect, rect2: DOMRect, proximity = 0):
const sx = sign(dx);
hit.delta.x = px * sx;
hit.normal.x = sx;
hit.pos.x = rect1.x + (rect1.width / 2) * sx;
hit.pos.y = rect2.y;
hit.pos.x = center1.x + (rect1.width / 2) * sx;
hit.pos.y = center2.y;
} else {
const sy = sign(dy);
hit.delta.y = py * sy;
hit.normal.y = sy;
hit.pos.x = rect2.x;
hit.pos.y = rect1.y + (rect1.height / 2) * sy;
hit.pos.y = center2.y + (rect1.height / 2) * sy;
}
return hit;