Component for detecting collisions
Include the scripts in html as follow:
<script src="https://unpkg.com/collision-engine/public/collision-engine.js"></script>
Add to package.json
:
"dependencies": {
...
"collision-engine": "^1.0.0",
...
}
Use Browserify to make classes available in browser
In package.json
:
"scripts": {
...
"browserify": "browserify browserify/main.js -s dok-lib -o public/gen/compact.js",
...
},
In browserify/main.js
:
const { CollisionMixer } = require('collision-engine');
module.exports = {
CollisionMixer,
};
Component for detecting collisions.
- First setup the collision mixer.
const collisionMixer = new CollisionMixer({
horizontal: true, vertical: true, deep: true,
getCollisionBox: box => box,
calculateCollisionBox: (box, collisionBox) => box.processBox(collisionBox),
onEnter: (body, other) => body.onEnter(other),
onLeave: (body, other) => body.onLeave(other),
onCollide: (body, other, xPush, yPush, zPush) => body.onCollide(other),
});
- horizontal[default=false]: if true, we enable collisions on the x-axis.
- vertical[default=false]: if true, we enable collisions on the y-axis.
- deep[default=false]: if true, we enable collisions on the z-axis.
- getCollisionBox[optional]: if set, it's a callback that takes a body should return an object that contains: {left, right, top, bottom, close, far} (depending on the axis enabled).
- calculateCollisionBox[optional]: a callback that takes a body and a collisionBox. Instead of returning the collisionBox, it must set the {left, right, top, bottom, close, far} properties (depending on axis enabled). This is similar to getCollisionBox but it lets you set the box without instantiation, for better performance. Note that if getcollisionBox is passed, this is ignored.
- onEnter: callback triggered when a body enters collision with other.
- onLeave: callback triggered when a body leaves collision (stops overlapping).
- onCollide: callback triggered every frame as long as two bodies overlap. xPush, yPush, zPush determines how deep both objects overlap.
- Add bodies to check for collision.
collisionMixer.add(body);
- Call refresh to check for check for collisions and allow triggering of events.
collisionMixer.refresh(time);
Note that time is a number change must change every time refresh is called. Typically, the time from requestAnimationFrame parameter is used.
I tried to make this algorithm perform as fast as I can know how to make it. I'm sure there are even faster algorithms out there, but I think the one I use here is not too bad. (Beats brute force O(
- Pick up all box corner coordinates on the x-axis, on the y-axis, and on the z-axis. Each box has two markers on each axis.
- Sort all axis ( O(
$log(n)$ ) - Iterate through an axis. When we hit a box's marker, put it in a hash. When we hit that box's second marker, remove it from the hash.
- Each time we add a box into the hash, look through the whole hash. Every elements currently in that hash overlap.
- This might seem like a costly operation, but in an environment where at most 2-3 elements can overlap, it's just ends up being O(n).
- Perform callbacks on every box overlapping.