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 { 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();
}
} }
} }

View File

@ -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;