3
\$\begingroup\$

I have a game engine created in javascript (https://jsfiddle.net/4gqsq8wf/) which uses collision detection via the Separating Axis Theorem. Currently, it does not have any means of resolving velocity upon the impact of multiple objects. Many posts have stated on this site that the post-collision velocity of an object is simply the angle of reflection. (For example: https://stackoverflow.com/questions/573084/how-to-calculate-bounce-angle) However, this requires knowing the angles of the surfaces contacting each other. I don't know how to figure out these, as the function I wrote only calculates the Minimum Translation Vector; how would I find the polygon faces involved in a collision?

Layman's terms would be appreciated.

Edit: Would this be the collision normal?

\$\endgroup\$
  • \$\begingroup\$ I'd like to hear the right answer to this too but if there isn't a good solution, you could always do reflection as if they were two spheres colliding. It wouldnt be great for objects that were a lot longer or shorter on a single axis, and it isn't very physically accurate at all, but it definitely could be good enough in certain circumstances. It also is pretty quick to calculate! \$\endgroup\$ – Alan Wolfe Jul 14 '15 at 3:04
  • \$\begingroup\$ Rectangles would definitely be an edge case with that method. \$\endgroup\$ – Someone Jul 14 '15 at 15:00
  • \$\begingroup\$ This question and answers look relevant: gamedev.stackexchange.com/questions/16827/… \$\endgroup\$ – Alan Wolfe Jul 14 '15 at 15:22
  • \$\begingroup\$ The top response from that site brushes over the process with this statement here: 'Step 2: Divide each polygon along the line connecting these points. The half of the polygon that faces the other polygon along the motion vector is the "forward hull". This is the only part of the polygon that can possibly collide.' Again, how would you determine what vertices were on said 'forward hull'? \$\endgroup\$ – Someone Jul 14 '15 at 18:33
1
\$\begingroup\$

The Minimum Translation Vector is the collision normal most of the time.

However, I believe that without velocity information it is impossible to get the collision normal correct all the time. Consider that you have 2 aabbs colliding. One aabb is stationary. In one case, the other aabb moves from the left and hits the first aabb. The correct collision normal would be -x. In second case, the aabb moves from top and hits the stationary aabb. The collision normal would in in y axis. However, the 2 aabbs in both cases may land in the exact same position for your SAT test. And thus it is going to return the same MTV. As you see, you can get the same MTV despite having different correct collision normals.

If you really need collision normals, then you need a sweep test: such as this link: http://volgogradetzzz.blogspot.ca/2011/05/swept-sat.html.

Basically, with velocity information, we can calculate the time which each axis/edge of object is hit. Then the collision normal would be the latest time in which a axis/edge is hit.

\$\endgroup\$
1
\$\begingroup\$

My collision detection + reflection works just fine (see here). First you need a boundary box as you will have this already implemented. Boundary boxes are generally vertices having each in 2D an X and Y coordinate which define the outer structure of an object.

To generally calculate the angle of a boundary, I use in C++ an atan function, which returns the angle of a vector within a coordinate system:

double GetAngleofVector(vector2 aVec)
    {
    double angle = atan2(aVec.Y,aVec.X)
    return angle;
    }

However, sticking strictly to vectors , this is unnecessary and much easier to do with raw vector calculations. Now, if you have a collision detection in place (e.g. SAT), to calculate the reflection angle, you need to think of thee cases and their 'physics'.

A) a circle reflected against a circle B) a circle reflected against a boundary C) a boundary reflected against a boundary i) corner of Object 1 hits boundary of Object 2 ii) corner of Object 1 hits corner of boundary 2 iii) same as i, only reverse objects and hence calculations stay the same

There are good tutorials available for circle vs boundary (see e.g. here and here) and for rectangle vs rectangle with added rotation (see. e.g. here with Java Code sample).

For the simple case--bouncing of a wall, you need to get the projection of your velocity vector onto both the direction of the boundary and the direction perpendicular to the boundary. Call the boundary "colliding_boundary", simply a vector of the two vertices that span it. (Construct your own vector class "vector2" with the float member variables x and y).

vector2 colliding_boundary;
colliding_boundary.x = vertice_2.x-vertice_1.x
colliding_boundary.y = vertice_2.y-vertice_1.y

To obtain the normal from any vector given, I use the standard formula. In 2D space that's relatively easy:

vector2 GetNormal( vector2 const &A )
    {
    return vector2(-A.Y,A.X);
    } 

However, two more very useful formulas for 2D game engine development are the dot product and the unit vector along some original vector.

vector2 GetProjection(vector2 const &A, vector2 const &B)
    {
    vector2 dir=GetUnitVector(B);
    double p_length = DotProduct(A,dir);
    vector2 proj = p_length*dir;
    return proj;
    }

vector2 GetPerpendProjection(vector2 const &A, vector2 const &B)
    {
    vector2 dir=GetUnitVector(B);
    double p_length = DotProduct(A,dir);
    vector2 at = p_length*dir;
    vector2 an = A-at;
    return an;
    }

Finally, I apply two compact functions to obtain the two aforementioned projections of your object's original velocity vector.

vector2 GetProjection(vector2 const &A, vector2 const &B)
    {
    vector2 dir=GetUnitVector(B);
    double p_length = DotProduct(A,dir);
    vector2 proj = p_length*dir;
    return proj;
    }

vector2 GetPerpendProjection(vector2 const &A, vector2 const &B)
    {
    vector2 dir=GetUnitVector(B);
    double p_length = DotProduct(A,dir);
    vector2 at = p_length*dir;
    vector2 an = A-at;
    return an;
    }

Passing your velocity vector and boundary into those two functions gets you the two necessary vectors to get your object bouncing.

Remember, the resulting velocity is simply the reverse of the vector projection that is perpendicular to the wall (reflection!), while the velocity along the wall is kept.

So your final velocity would be:

vector2 v_final = GetProjection(speed_vector, colliding_boundary) - GetPerpendProjection(speed_vector, colliding_boundary).

For visualization I added a the demo link of my own game (mpeg) above. Notice the yellow, red, blue and white vectors being drawn at runtime collision and representing, in order, the object's original velocity, boundary perpendicular projection, boundary projection and final velocity. (Note, my object is also rotating, but ignore this for now.)

\$\endgroup\$

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.