collision
This commit is contained in:
parent
f5bad0b176
commit
b40ba06404
|
|
@ -22,31 +22,55 @@
|
||||||
folk-shape {
|
folk-shape {
|
||||||
border: 2px solid black;
|
border: 2px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
border: 1px solid grey;
|
||||||
|
max-width: 30ch;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
|
<p>
|
||||||
<folk-shape x="200" y="200" width="50" height="50"></folk-shape>
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
|
||||||
<folk-shape x="200" y="275" width="50" height="50"></folk-shape>
|
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
<folk-shape x="200" y="150" width="50" height="50"></folk-shape>
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||||
<folk-shape x="200" y="100" width="50" height="50"></folk-shape>
|
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">
|
<script type="module">
|
||||||
import '../src/standalone/folk-shape.ts';
|
import { FolkShape } from '../src/standalone/folk-shape.ts';
|
||||||
import { aabbHitDetection } from '../src/common/collision.ts';
|
import { aabbHitDetection } from '../src/common/collision.ts';
|
||||||
|
|
||||||
const shapes = Array.from(document.querySelectorAll('folk-shape'));
|
const shapes = Array.from(document.querySelectorAll('folk-shape'));
|
||||||
|
|
||||||
|
const getBoundingBox = (el) => (el instanceof FolkShape ? el.getTransformDOMRect() : el.getBoundingClientRect());
|
||||||
|
|
||||||
function handleCollision(e) {
|
function handleCollision(e) {
|
||||||
for (const shape of shapes) {
|
for (const shape of shapes) {
|
||||||
if (shape === e.target) continue;
|
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;
|
if (hit === null) continue;
|
||||||
|
|
||||||
shape.x -= hit.delta.x;
|
if (shape instanceof FolkShape) {
|
||||||
shape.y -= hit.delta.y;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,22 @@ export class Hit {
|
||||||
normal: Point = { x: 0, y: 0 };
|
normal: Point = { x: 0, y: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Test collisions of axis-aligned bounding boxes. */
|
const center = (rect: DOMRectReadOnly) => ({
|
||||||
export function aabbHitDetection(rect1: DOMRect, rect2: DOMRect, proximity = 0): Hit | null {
|
x: rect.x + rect.width / 2,
|
||||||
const dx = rect2.x - rect1.x;
|
y: rect.y + rect.height / 2,
|
||||||
const px = rect2.width / 2 + rect1.width / 2 - Math.abs(dx);
|
});
|
||||||
|
|
||||||
|
/** 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;
|
if (px <= 0) return null;
|
||||||
|
|
||||||
const dy = rect2.y - rect1.y;
|
const dy = center2.y - center1.y;
|
||||||
const py = rect2.height / 2 + rect1.height / 2 - Math.abs(dy);
|
const py = (rect2.height + rect1.height) / 2 - Math.abs(dy);
|
||||||
|
|
||||||
if (py <= 0) return null;
|
if (py <= 0) return null;
|
||||||
|
|
||||||
const hit = new Hit();
|
const hit = new Hit();
|
||||||
|
|
@ -32,14 +38,14 @@ export function aabbHitDetection(rect1: DOMRect, rect2: DOMRect, proximity = 0):
|
||||||
const sx = sign(dx);
|
const sx = sign(dx);
|
||||||
hit.delta.x = px * sx;
|
hit.delta.x = px * sx;
|
||||||
hit.normal.x = sx;
|
hit.normal.x = sx;
|
||||||
hit.pos.x = rect1.x + (rect1.width / 2) * sx;
|
hit.pos.x = center1.x + (rect1.width / 2) * sx;
|
||||||
hit.pos.y = rect2.y;
|
hit.pos.y = center2.y;
|
||||||
} else {
|
} else {
|
||||||
const sy = sign(dy);
|
const sy = sign(dy);
|
||||||
hit.delta.y = py * sy;
|
hit.delta.y = py * sy;
|
||||||
hit.normal.y = sy;
|
hit.normal.y = sy;
|
||||||
hit.pos.x = rect2.x;
|
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;
|
return hit;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue