3
\$\begingroup\$

update: new diagram and updated description

collision angle and body angle

I have a contact listener set up to try and determine the side that a collision happened at relative to the a bodies rotation. One way to solve this is to find the value of the yellow angle between the red and blue vectors drawn above. The angle can be found by taking the arc cosine of the dot product of the two vectors (Evan pointed this out). One of my points of confusion is the difference in domain of the atan2 function html canvas coordinates and the Box2d rotation information. I know I have to account for this somehow... SS below

questions:

  • Does Box2D provide these angles more directly in the collision information?
  • Am I even on the right track? If so, any hints?

I have the following javascript so far:

Ship.prototype.onCollide = function (other_ent,cx,cy) {

  var pos = this.body.GetPosition();

  //collision position relative to body
  var d_cx = pos.x - cx;
  var d_cy = pos.y - cy;

  //length of initial vector
  var len = Math.sqrt(Math.pow(pos.x -cx,2) + Math.pow(pos.y-cy,2));

  //body angle - can over rotate hence mod 2*Pi
  var ang = this.body.GetAngle() % (Math.PI * 2);

  //vector representing body's angle - same magnitude as the first
  var b_vx = len * Math.cos(ang);
  var b_vy = len * Math.sin(ang);

  //dot product of the two vectors
  var dot_prod = d_cx * b_vx + d_cy * b_vy;

  //new calculation of difference in angle - NOT WORKING!
  var d_ang = Math.acos(dot_prod);

  var side; 
  if (Math.abs(d_ang) < Math.PI/2 )
    side = "front";
  else
    side = "back"; 

  console.log("length",len);
  console.log("pos:",pos.x,pos.y);
  console.log("offs:",d_cx,d_cy);
  console.log("body vec",b_vx,b_vy);      
  console.log("body angle:",ang);
  console.log("dot product",dot_prod);
  console.log("result:",d_ang);      
  console.log("side",side);
  console.log("------------------------");

}
\$\endgroup\$
  • 1
    \$\begingroup\$ acos of the dot product of a vector passing through the point of collision, and your objects facing vector. This will allow you to efficiently get the angle between these two vectors. \$\endgroup\$ – Evan May 6 '14 at 14:47
  • \$\begingroup\$ thx for the tip! now.. if i can just figure out how to determine the objects facing vector properly. I updated the code above to reflect what i have so far.. seems like there is still something missing. \$\endgroup\$ – jorb May 7 '14 at 4:56
  • \$\begingroup\$ I’m afraid I don’t understand the drawings. What is the blue rectangle? The blue line? The black circle? The two black lines? The red line? What is actually colliding with what? For this answer to be useful to other people, it should be a bit more clear what you are asking. \$\endgroup\$ – sam hocevar May 7 '14 at 10:14
  • \$\begingroup\$ updated diagram and description @SamHocevar \$\endgroup\$ – jorb May 7 '14 at 23:15
2
\$\begingroup\$

I have a result that works. Some things that I didn't get right initially..

  • efficient formula (thx user Evan)
  • possible negative body rotation
  • extra 90° where Box2D and html canvas rotation begins

extra 90° where Box2D and html canvas rotation begins


Ship.prototype.onCollide = function (other_ent,cx,cy) {

  var pos = this.body.GetPosition();

  //collision position relative to body
  var d_cx = pos.x - cx;
  var d_cy = pos.y - cy;

  //length of initial vector
  var len = Math.sqrt(Math.pow(pos.x -cx,2) + Math.pow(pos.y-cy,2));

  //body angle - can over rotate hence mod 2*Pi
  var ang = this.body.GetAngle() % (Math.PI * 2);

  //adjust negative rotation
  if (ang < 0) { ang = (Math.PI * 2) + ang; }

  //vector representing body's angle - same magnitude as the first
  var b_vx = Math.cos(ang- Math.PI/2);
  var b_vy = Math.sin(ang- Math.PI/2);

  //dot product of the two vectors
  var dot_prod = d_cx * b_vx + d_cy * b_vy;
  dot_prod /= len;

  //resulting angle
  var d_ang = Math.acos(dot_prod);

  var side;
  if (Math.abs(d_ang) > Math.PI/2 )
    side = "front";
  else
    side = "back";

}
\$\endgroup\$
  • \$\begingroup\$ One more small change I'd make is to calculate Math.PI/2 once and save the result. This will reduce the number of costly floating point divisions. (The same can be done for Math.PI * 2 too, but the divisions are by far the more costly). \$\endgroup\$ – DFreeman May 9 '14 at 9:36
  • \$\begingroup\$ good point @DFreeman thx. lead me to search the box2dweb code to see that it had at least done that also :) \$\endgroup\$ – jorb May 9 '14 at 11:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.