Skip to content

Instantly share code, notes, and snippets.

@kittykatattack
Created August 27, 2014 17:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kittykatattack/befdddc4985a9a43bf68 to your computer and use it in GitHub Desktop.
Save kittykatattack/befdddc4985a9a43bf68 to your computer and use it in GitHub Desktop.
A function that bounces apart two moving circles
/*
# movingCircleCollision
Use it to make two moving circles bounce off each other.
Parameters:
a. A sprite object with `x`, `y` `centerX`, `centerY` and `radius` properties.
b. A sprite object with `x`, `y` `centerX`, `centerY` and `radius` properties.
The sprites can contain an optional mass property that should be greater than 1.
*/
movingCircleCollision = function(c1, c2) {
var combinedRadii, overlap, xSide, ySide,
//`s` refers to the collision surface
s = {},
p1A = {}, p1B = {}, p2A = {}, p2B = {},
hit = false;
//Apply mass, if the circles have mass properties
c1.mass = c1.mass || 1;
c2.mass = c2.mass || 1;
//Set `global` to a default value of `true`
if(global === undefined) global = true;
//Calculate the vector between the circles’ center points
s.vx = c2.centerX - c1.centerX;
s.vy = c2.centerY - c1.centerY;
//Find the distance between the circles by calculating
//the vector's magnitude (how long the vector is)
s.magnitude = Math.sqrt(s.vx * s.vx + s.vy * s.vy);
//Add together the circles' combined half-widths
combinedRadii = c1.radius + c2.radius;
//Figure out if there's a collision
if (s.magnitude < combinedRadii) {
//Yes, a collision is happening
hit = true;
//Find the amount of overlap between the circles
overlap = combinedRadii - s.magnitude;
//Add some "quantum padding" to the overlap
overlap += 0.3;
//Normalize the vector.
//These numbers tell us the direction of the collision
s.dx = s.vx / s.magnitude;
s.dy = s.vy / s.magnitude;
//Find the collision vector.
//Divide it in half to share between the circles, and make it absolute
s.vxHalf = Math.abs(s.dx * overlap / 2);
s.vyHalf = Math.abs(s.dy * overlap / 2);
//Find the side that the collision if occurring on
(c1.x > c2.x) ? xSide = 1 : xSide = -1;
(c1.y > c2.y) ? ySide = 1 : ySide = -1;
//Move c1 out of the collision by multiplying
//the overlap with the normalized vector and adding it to
//the circle's positions
c1.x = c1.x + (s.vxHalf * xSide);
c1.y = c1.y + (s.vyHalf * ySide);
//Move c2 out of the collision
c2.x = c2.x + (s.vxHalf * -xSide);
c2.y = c2.y + (s.vyHalf * -ySide);
//1. Calculate the collision surface's properties
//Find the surface vector's left normal
s.lx = s.vy;
s.ly = -s.vx;
//2. Bounce c1 off the surface (s)
//Find the dot product between c1 and the surface
var dp1 = c1.vx * s.dx + c1.vy * s.dy;
//Project c1's velocity onto the collision surface
p1A.x = dp1 * s.dx;
p1A.y = dp1 * s.dy;
//Find the dot product of c1 and the surface's left normal (s.l.x and s.l.y)
var dp2 = c1.vx * (s.lx / s.magnitude) + c1.vy * (s.ly / s.magnitude);
//Project the c1's velocity onto the surface's left normal
p1B.x = dp2 * (s.lx / s.magnitude);
p1B.y = dp2 * (s.ly / s.magnitude);
//3. Bounce c2 off the surface (s)
//Find the dot product between c2 and the surface
var dp3 = c2.vx * s.dx + c2.vy * s.dy;
//Project c2's velocity onto the collision surface
p2A.x = dp3 * s.dx;
p2A.y = dp3 * s.dy;
//Find the dot product of c2 and the surface's left normal (s.l.x and s.l.y)
var dp4 = c2.vx * (s.lx / s.magnitude) + c2.vy * (s.ly / s.magnitude);
//Project c2's velocity onto the surface's left normal
p2B.x = dp4 * (s.lx / s.magnitude);
p2B.y = dp4 * (s.ly / s.magnitude);
//Calculate the bounce vectors
//Bounce c1
//using p1B and p2A
c1.bounce = {};
c1.bounce.x = p1B.x + p2A.x;
c1.bounce.y = p1B.y + p2A.y;
//Bounce c2
//using p1A and p2B
c2.bounce = {};
c2.bounce.x = p1A.x + p2B.x;
c2.bounce.y = p1A.y + p2B.y;
//Add the bounce vector to the circles' velocity
//and add mass if the circle has a mass property
c1.vx = c1.bounce.x / c1.mass;
c1.vy = c1.bounce.y / c1.mass;
c2.vx = c2.bounce.x / c2.mass;
c2.vy = c2.bounce.y / c2.mass;
}
return hit;
};
@kittykatattack
Copy link
Author

//If you have an array called `circles` full of circle objects, 
//you can test them for collisions inside a game loop like this:

for (var i = 0; i < circles.length; i++) {
  //The first circle to use in the collision check 
  var c1 = circles[i];
  for (var j = i + 1; j < circles.length; j++) {
    //The second circle to use in the collision check 
    var c2 = circles[j];
    //Check for a collision and bounce the circles apart if
    //they collide. Use an optional `mass` property on the circle object
    //to affect the bounciness of each circle
    movingCircleCollision(c1, c2);
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment