JavaScript Polygon Collision Detection

collision-detection, game-physics, html5-canvas, javascript

Solution

Because there are no canvas clip properties for retrieving intersection area. I would suggest next solution. Use one of js libraries for poligon intersection calculation, for example Greiner-Hormann. Using this lib, you can easily intersect you shapes and detect collision(if intersection result is not null then collision exists).

example:

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');

function drawTriangle(trianglePoints, color)
{
  ctx.beginPath();
  ctx.moveTo(trianglePoints[0].x, trianglePoints[0].y);
  ctx.lineTo(trianglePoints[1].x, trianglePoints[1].y); 
  ctx.lineTo(trianglePoints[2].x, trianglePoints[2].y);  
  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
 }

function getTriangle(size, startPointX, startPointY)
{
  return [{x:startPointX,y:startPointY},
          {x:startPointX + size,y:startPointY},
          {x:startPointX,y:startPointY + size},
          {x:startPointX,y:startPointY}];
}

//sample triangles
var triangle1 = getTriangle(50,100,100);
var triangle2 = getTriangle(50,100,90);
var triangle3 = getTriangle(50,200,100);
var triangle4 = getTriangle(50,280,90);

//draw all triangles
drawTriangle(triangle1,'#d3d3d3');
drawTriangle(triangle2,'#e3e3e3');
drawTriangle(triangle3,'red');
drawTriangle(triangle4,'blue');

//intersaction results
console.log("intersection exists");
console.log(greinerHormann.intersection( triangle1 , triangle2));
console.log("intersection not exists result of intersaction - null");
console.log(greinerHormann.intersection( triangle3 , triangle2));
<script src="https://cdn.rawgit.com/w8r/GreinerHormann/master/dist/greiner-hormann.min.js"></script>
<canvas id="myCanvas" width="578" height="200"></canvas>

Problem

I am working on an asteroids-like arcade game using HTML's canvas and JavaScript. I currently have a bunch of randomly generated shapes ("asteroids") with a random number of points (3, 4, or 5) and a random size at random locations. I am trying set up a collision detection system with these polygons. I have been using SAT.js (https://github.com/jriecken/sat-js) for this. However, I can't accurately seem to draw the invisible, collision polygons around the actual polygons rendered on the screen. Here is what I have in my asteroid class where I am rendering the asteroids. I am currently only testing with 3 points in the shapes (triangles). I turned the 4 and 5 point asteroids off. ``` ctx.moveTo(0, 0); ctx.lineTo(10 + size, 20); ctx.lineTo(10 + size, 20 + size); ctx.closePath(); ``` Here is the corresponding SAT.js code. ``` /** * @function createCollisionPolygon * Traces the outline of the asteroid to allow it to detect collisions * based on the number of points the shape has (3, 4, or 5) * @param {asteroid} The asteroid to make collision detectable * @return The traced polygon */ function createCollisionPolygon(asteroid) { var V = SAT.Vector; var P = SAT.Polygon; var polygon; switch(asteroid.randomNumPoints) { // 3 point polygon case 3: polygon = new P(new V(asteroid.position.x, asteroid.position.y), [ new V(10 + asteroid.size, 0), new V(asteroid.position.x,asteroid.position.y), new V(10 + asteroid.size, 20 + asteroid.size) ]); break; } return polygon; } /** * @function checkCollision * Checks for collisions between any two asteroids * @param {polygon1} The first asteroid * @param {polygon2} The next asteroid * @return True if there was a collision, false otherwise */ function checkCollision(polygon1, polygon2) { var response = new SAT.Response(); var collided = SAT.testPolygonPolygon(polygon1, polygon2, response); return collided; } ``` Which is later being called here: ``` for(var i = 0; i < asteroids.length - 1; i++) { var asteroid1 = asteroids[i]; var asteroid2 = asteroids[i+1]; // Trace an invisible outline around each asteroid var polygon1 = createCollisionPolygon(asteroid1); var polygon2 = createCollisionPolygon(asteroid2); // console.log("Polygon 1: "+ console.log(polygon1.points[0] // + console.log(polygon1.points[1]) + console.log(polygon1.points[2]))); // console.log("Polygon 2: " + console.log(polygon2.points[0] // + console.log(polygon2.points[1]) + console.log(polygon2.points[2]))); // Check if there is a collision if(checkCollision(polygon1, polygon2)) { asteroid1.color = 'red'; asteroid2.color = 'red'; console.log("Collision detected."); } } ``` Any help would be appreciated - I've been trying to figure this out for days. Thanks!

Original source