Sam
Sam

Reputation: 313

How to detect collisions between fast moving objects

Generally to detect collisions in canvas games I use something like:

function collides(a, b) {
   return a.x < b.x + b.width &&
     a.x + a.width > b.x &&
     a.y < b.y + b.height &&
     a.y + a.height > b.y;
}

But this only detects collisions if the objects are touching at the time the frame is processed. If I have a sprite whose speed (in pixels/frame) is greater than the width of an obstacle in its path, it will pass through the obstacle without the collision being detected.

How would I go about checking what's in between the sprite and its destination?

Upvotes: 11

Views: 2965

Answers (3)

Shem
Shem

Reputation: 29

check this out. try moving rect 1 with arrow keys and if it touches rect 2 it will alert "collided".

var rect1x = 0;
var rect1y = 0;
var rect1height = 10;
var rect1width = 10;
var rect2x = 200;
var rect2y = 0;
var rect2height = 10;
var rect2width = 10;
var speedX = 0;
var speedY = 0;
var ctx = document.getElementById("canvas").getContext("2d");
var interval = setInterval(function() {
document.addEventListener("keydown", function(e) {
if (e.key == "ArrowLeft") {
speedX = -1;
}
if (e.key == "ArrowRight") {
speedX = 1;
}
if (e.key == "ArrowUp") {
speedY = -1;
}
if (e.key == "ArrowDown") {
speedY = 1;
}
});
document.addEventListener("keyup", function() {
speedX = 0;
speedY = 0;
});
ctx.clearRect(rect1x, rect1y, rect1width, rect1height);
rect1x += speedX;
rect1y += speedY;
ctx.fillStyle = "blue";
ctx.fillRect(rect1x, rect1y, rect1width, rect1height);
ctx.fillStyle = "red";
ctx.fillRect(rect2x, rect2y, rect2width, rect2height);
if (((rect1x + rect1width > rect2x) && (rect1x < rect2x + rect2width)) && ((rect1y + rect1height > rect2y) && (rect1y < rect2y + rect2height))) {
clearInterval(interval);
alert("collided");
}
}, 0);
<canvas id="canvas" height="400" width="400" style="border: 1px solid black"></canvas>

Upvotes: -1

Kornel
Kornel

Reputation: 100110

That's a generally a hard problem and for high-quality solution something like Box 2D library will be useful.

A quick and dirty solution (that gives false positives on diagonally moving objects) — check collision between bounding boxes that cover position of object in current and previous frame.

Instead of a.x use min(a.x, a.x - a.velocity_x), instead of a.x + a.width use max(a.x + a.width, a.x + a.width - a.velocity_x), etc.

If the object that is moving fast is small (a bullet), then test collision between line (from its origin to origin + velocity) and boxes of other objects.

Upvotes: 2

Dek Dekku
Dek Dekku

Reputation: 1461

You should use the whole area swept (in the update interval) by the moving object as the bounding box to check against the obstacle.

Upvotes: 0

Related Questions