How to do this collision response?

Started by
7 comments, last by oliii 14 years, 7 months ago
I want this to happen in my game: Collision_Response_question.jpg 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.
Advertisement
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;
I don't know if this describes the same emthod as the previous poster described but what you want can be found in this paper:

http://www.peroxide.dk/papers/collision/collision.pdf

its in chapter 4.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

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.
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.
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 vertexfloat dist = sqrt( pow( circ.x - vert.x, 2 ) + pow( circ.y - vert.y, 2 ) );// compareif( dist <= circ.radius() )  collide();


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

// find distance from center of circle to vertexfloat dist = pow( circ.x - vert.x, 2 ) + pow( circ.y - vert.y, 2 );// compareif( dist <= circ.radius()*circ.radius() )  collide();
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?
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
-------------------------http://www.roachpuppy.com
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 ?
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.

Everything is better with Metal.

This topic is closed to new replies.

Advertisement