joshuaaron
joshuaaron

Reputation: 906

elastic 2d ball collision using angles

Yes theres a few threads on this, but not many using angles and I'm really trying to figure it out this way, I'm now stuck on setting the new velocity angles for the circles. I have been looking at: http://www.hoomanr.com/Demos/Elastic2/ as a reference to it, but I'm stuck now.

Can anybody shed some light?

cx/cy/cx2/cy2 = center x/y for balls 1 and 2. vx/vy/vx2/vy2 = velocities for x/y for balls 1 and 2

function checkCollision() {
var dx = cx2 - cx;  //distance between x
var dy = cy2 - cy;  // distance between y
var distance = Math.sqrt(dx * dx + dy * dy);

var ang = Math.atan2(cy - cy2, cx - cx2);

// was displaying these in a div to check
var d1 = Math.atan2(vx, vy); //ball 1 direction
var d2 = Math.atan2(vx2, vy2); //ball 2 direction

// this is where I am stuck, and i've worked out this is completely wrong now
// how do i set up the new velocities for 
var newvx = vx * Math.cos(d1 - ang);
var newvy = vy * Math.sin(d1 - ang);
var newvx2 = vx2 * Math.cos(d2 - ang); 
var newvy2 = vy2 * Math.sin(d2 - ang);


if (distance <= (radius1 + radius2)) {
    //Set new velocity angles here at collision..
}

Heres a codepen link:

http://codepen.io/anon/pen/MwbMxX

Upvotes: 2

Views: 2677

Answers (1)

GameAlchemist
GameAlchemist

Reputation: 19294

A few directions :

• As mentioned in the comments, use only radians (no more *180/PI).
• atan2 takes y as first param, x as second param.

var d1 = Math.atan2(vy, vx); //ball 1 direction in angles
var d2 = Math.atan2(vy2, vx2); //ball 2 direction in angles

• to rotate a vector, compute first its norm, then only project it with the new angle :

var v1 = Math.sqrt(vx*vx+vy*vy);
var v2 = Math.sqrt(vx2*vx2+vy2*vy2);

var newvx = v1 * Math.cos(d1 - ang);
var newvy = v1 * Math.sin(d1 - ang);
var newvx2 = v2 * Math.cos(d2 - ang); 
var newvy2 = v2 * Math.sin(d2 - ang);

• You are detecting the collision when it already happened, so both circles overlap, but you do NOT solve the collision, meaning the circles might still overlap on next iteration, leading to a new collision and a new direction taken, ... not solved, etc.. -->> You need to ensure both circles are not colliding any more after you solved the collision.

• Last issue, but not a small one, is how you compute the angle. No more time for you sorry, but it would be helpful both for you and us to build one (several) scheme showing how you compute the angles.

Updated (but not working) codepen here :

http://codepen.io/anon/pen/eNgmaY

Good luck.

Edit :

Your code at codepen.io/anon/pen/oXZvoe simplify to this :

 var  angle = Math.atan2(dy, dx),
      spread = minDistance - distance,
      ax = spread * Math.cos(angle),
      ay = spread * Math.sin(angle);

    vx -= ax;
    vy -= ay;
    vx2 += ax;
    vy2 += ay;

You are substracting the gap between both circles from the speed. Since later you add the speed to the position, that will do the spatial separation (=> no more collision).
I think to understand what vx-=ax means, we have to remember newton : v = a*t, where a is the acceleration, so basically doing vx=-ax means applying a force having the direction between both centers as direction, and the amount by which both circle collided (spread) as intensity. That amount is obviously quite random, hence the numerical instability that you see : sometimes a small effect, sometimes a big one.

look here for a constant punch version :

http://codepen.io/anon/pen/WvpjeK

var angle = Math.atan2(dy, dx),
  spread = minDistance - distance,
  ax = spread * Math.cos(angle),
  ay = spread * Math.sin(angle);

// solve collision (separation)
cx -= ax;
cy -= ay;

// give a punch to the speed
var punch = 2;

vx -= punch*Math.cos(angle);
vy -= punch*Math.sin(angle);
vx2 += punch*Math.cos(angle);
vy2 += punch*Math.sin(angle);

Upvotes: 3

Related Questions