Sign in to follow this  
mazelle

How to do this collision response?

Recommended Posts

I want this to happen in my game: [URL=http://www.4shared.com/file/131963424/63cebdc5/Collision_Response_question.html][IMG]http://dc109.4shared.com/img/131963424/63cebdc5/Collision_Response_question.jpg[/IMG][/URL] My current solution is to look for the edge closest to the moving (red) object and then project the displacement along that edge. My algorithm for 'look for the edge closest to the moving (red) object' is this: 1. Get nearest vertex from black object (I'm using OBBs, so only four) to red's position (the center). 2. Get the edge retrieved from #1 (there are two) such that the ray from the black's center to red's center has an intersection. But this doesn't not always work. If the two edges intersects the ray (red object is on the corner), the algorithm may give the wrong edge and the displacement projection will be incorrect. Any ideas? I'm using SAT. I'm also looking into the axis with the smallest overlap size if its useful. But I'm sleepy now and I can't think. Thanks in advance.

Share this post


Link to post
Share on other sites
Assuming you find a robust way to compute the contact position and normal.

Project the velocity onto the normal, remove projected velocity from original velocity, result: no velocity in normal direction.

Source:
NormalVelocity = ContactNormal * Dot(ContactNormal, CurrentVelocity);
ResultantVelocity = CurrentVelocity - NormalVelocity;

Share this post


Link to post
Share on other sites
I'm not sure how your physics work but if they're similar to how box2d does things you can have a contact response (function pointer) that is called when a collision is detected. Just check if the collision happened anywhere near the side of your object, then cancel the horizontal response or velocity. and if needed make the vertical velocity hapen in the direction you want it to.

Share this post


Link to post
Share on other sites
You are going to also need to detect for a circle/corner collision. It's a special case, but it is easier to do than circle/side. Just use the coordinates of the vertices of your OBB and compare with the center of the circle.



// find distance from center of circle to vertex
float dist = sqrt( pow( circ.x - vert.x, 2 ) + pow( circ.y - vert.y, 2 ) );

// compare
if( dist <= circ.radius() )
collide();



You can actually make this code more efficient by comparing the distances squared.



// find distance from center of circle to vertex
float dist = pow( circ.x - vert.x, 2 ) + pow( circ.y - vert.y, 2 );

// compare
if( dist <= circ.radius()*circ.radius() )
collide();

Share this post


Link to post
Share on other sites
Thanks to all of you.

Nice paper Nanoha. That's what I implemented and it's working now. Although for now it only works for objects that has more or less equal radius components. I tried testing it with elongated objects. It doesn't work well. I guess I need to transform the radius as well when rotated. But I also tried that, it didn't work as expected. Maybe I missed something. Any ideas to that?

Share this post


Link to post
Share on other sites
You pretty much described sliding planes. After calculating this plane (its normal is the vector between the point of contact and object center) and projecting your original destination onto it, you can calculate a new velocity vector to pass through your collision routines again. This is much more robust and realistic than messing with your velocity based on the colliding surfaces normal.

Here's a link to an excellent paper by Paul Nettle that goes into the subject in detail: http://www.informatik.uni-oldenburg.de/~trigger/papers/good/Fluid_Studios_Generic_Collision_Detection_for_Games_Using_Ellipsoids.pdf

Share this post


Link to post
Share on other sites
Quote:
Original post by Ouranos
You pretty much described sliding planes. After calculating this plane (its normal is the vector between the point of contact and object center) and projecting your original destination onto it, you can calculate a new velocity vector to pass through your collision routines again. This is much more robust and realistic than messing with your velocity based on the colliding surfaces normal.

Here's a link to an excellent paper by Paul Nettle that goes into the subject in detail: http://www.informatik.uni-oldenburg.de/~trigger/papers/good/Fluid_Studios_Generic_Collision_Detection_for_Games_Using_Ellipsoids.pdf


This paper seems to be GREAT !

I've not read it yet, but the multi-planes intersection problem has to be considered.

When your player/object bounding volume (in this case a sphere or an elipsoid) moves, it can happen that it collies with more than one plane. Or it can happen that, after having moved it to the new position, at that time it starts to collide with a new plane... so the process has to start again.

My solution was to do a loop with a limited number of iterations (5 or 10) which tries at every step to find a good position for all the planes, every time decreasing the displacement in order to help the sphere/elipsoid to find a good spot.

Obviously, you have to exploit some sort of spatial partitioning structure to avoid considering ALL your map/level triangles.

----

A considerable problem is the case when the sphere moves along a side but with the center outside the 'region' of the triangle.

Look at the picture:


If the sphere starts to move to the left, there will be a moment when the sphere intersect the corner of the wall, but the plane/sphere intersection test would return "no intersection".

To resolve this, I 'extend' the triangles. It works fine, but it's not perfect.

How do you handle this ?

Share this post


Link to post
Share on other sites
THere's a very easy solution for collision response with spheres. Find the point of contact on the other object (in your case, a box), which will be te point on the object the nearest to the sphere centre, and that produces your normal of collision.

Then you simply apply a simple 'slide' algorithm.


Vector collisionPoint;

extern bool SphereBoxCollide(const class Sphere& sphere, const class Box& box, Vector& collisionPoint);

if(SphereBoxCollide(sphere, box, collisionPoint))
{
Vector normal = (sphere.centre - collisionPoint).direction();
sphere.velocity -= normal * (sphere.velocity.dotProduct(normal));
}


There is no messing about edges, corners, special cases. All you need is calculate the closest point on the box to the sphere centre.

If you want to do a swept test, then it is more complicated, but you can try to implement Kasper Fauerby's algorithm, only you need to test against a polygon, not just a triangle (or replace your rectangle by two triangles).

as a side note, here is an example.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this