Hi everyone,
I am working on the collision response for some basic moving poly vs. static poly collision engine. Once I detect a hit, I calculate a new velocity vector, based on the current velocity, the direction of the edge being hit, aswell as bounce and friction values. This all works really fine except when I turn bounce completely off. Setting friction to 1.0 (can only be between 0 and 1), means NO friction. Setting bounce to 0 (can only be between 0 and 1) means NO bounce. What I do is I calculate the components of the new velocity vector that are perpendicular and orthogonal to the edge being hit, and then multiply them by bounce and friction factors, and then add the two vectors together. This all works well, except when I set bounce to 0. Weird stuff starts to happen and the program eventually crashes. The reason for this crash is rather complicated and I've figured it out, but what I can't figure out is this:
Take a look at my CalculateNewVelocity function (its simple vector maths):
Quote:
public static Vector2D CalculateNewVelocity(Vector2D currentVelocity, Vector2D minimumTranslationVector, double friction, double bounce)
{
Console.WriteLine("Now in CalculateNewVelocity. Start debug sequence...");
// Create copies of the sent vectors.
// The direction of the edge that is being hit is the normal of the MTV.
Vector2D collisionEdge = new Vector2D();
collisionEdge.X = -minimumTranslationVector.Y;
collisionEdge.Y = minimumTranslationVector.X;
Vector2D mtv = new Vector2D();
mtv.X = minimumTranslationVector.X;
mtv.Y = minimumTranslationVector.Y;
Console.WriteLine("MTV: x = {0}, y = {1}", mtv.X, mtv.Y);
Vector2D newVelocity;
// First, get the angle between the two vectors (convert to radians).
double dotProductResult = currentVelocity * collisionEdge;
// If they are facing away from each other, the edge should face the same way
// as the velocity, to make calculations easier.
if (dotProductResult < 0)
collisionEdge = collisionEdge * (-1);
double angle = CalculateTheAngle(currentVelocity, collisionEdge);
Console.WriteLine("Angle (in deg): {0}", angle);
angle = angle * Math.PI / 180;
Console.WriteLine("Angle (in rad): {0}", angle);
// Get magnitudes of v components parallel and orthogonal to the collisionEdge.
double vPar = currentVelocity.Length * Math.Cos(angle);
double vOrth = currentVelocity.Length * Math.Sin(angle);
Console.WriteLine("Magnitude of vPar = {0}", vPar);
Console.WriteLine("Magnitude of vOrth = {0}", vOrth);
// Calculate the component of the new vector that is parallel to the collisionEdge.
// For this, use the normalized direction of the collisionEdge (should point the right way now).
// The multiply be friction factor.
collisionEdge.Normalize();
Vector2D vNewPar = collisionEdge * vPar;
vNewPar = vNewPar * friction;
Console.WriteLine("vNewPar: x = {0}, y = {1}", vNewPar.X, vNewPar.Y);
// Calculate the component of the new vector that is orthogonal to the collisionEdge.
// For this, use the normalized MTV.
// The multiply by bounce factor.
mtv.Normalize();
Vector2D vNewOrth = mtv * vOrth;
vNewOrth = vNewOrth * bounce;
Console.WriteLine("vNewOrth: x = {0}, y = {1}", vNewOrth.X, vNewOrth.Y);
// Now simply add the two components.
newVelocity = vNewPar + vNewOrth;
return newVelocity;
}
I put a bunch of console statements in there so I could trace what was going on. Basically, when frictiong is 0 (1.0 for the friction value) and bounce is 0, the tile should just slide along the surface of the static polygon. It does this for a really short time and then crashes. The result of the crash is linked to the fact, that the newVelocity vector eventually gets messed up (After 5 iterations I've figured out).
Here is my main() code (not that important...all you need to know is I keep checking for collisions and calculating the newVelocity vector each time I get one. I get collisions even when its "sliding" along the surface).
Quote:
static void Main(string[] args)
{
// Initialize the polygons.
Polygon polygonA = new Polygon();
polygonA.AddVector(new Vector2D(110, 100));
polygonA.AddVector(new Vector2D(200, 120));
polygonA.AddVector(new Vector2D(190, 150));
polygonA.AddVector(new Vector2D(100, 130));
Polygon polygonB = new Polygon();
polygonB.AddVector(new Vector2D(210, 300));
polygonB.AddVector(new Vector2D(300, 320));
polygonB.AddVector(new Vector2D(290, 350));
polygonB.AddVector(new Vector2D(200, 330));
Vector2D velocity = new Vector2D(2, 4);
Console.WriteLine("Friction = 1.0, Bounce = 0.0");
double friction = 1.0;
double bounce = 0.0;
CollisionResult result = new CollisionResult();
result = SeperatingAxisClass.TestCollision(polygonA, polygonB);
while (!result.IsIntersecting)
{
polygonA += velocity;
result = SeperatingAxisClass.TestCollision(polygonA, polygonB);
}
Console.WriteLine("Current center of polygonA: x = {0}, y = {1}", polygonA.Center.X, polygonA.Center.Y);
velocity = CalculateNewVelocity(velocity, result.MinimumTranslationVector, friction, bounce);
Console.WriteLine("New velocity vector: x = {0}, y = {1}", velocity.X, velocity.Y);
for (int i = 0; i < 10; i++)
{
Console.WriteLine();
Console.WriteLine("Moving polygonA by velocity vector and checking for hit...");
polygonA += velocity;
result = SeperatingAxisClass.TestCollision(polygonA, polygonB);
if (result.IsIntersecting)
{
Console.WriteLine("Calculating new velocity vector...should be the same.");
velocity = CalculateNewVelocity(velocity, result.MinimumTranslationVector, friction, bounce);
Console.WriteLine("New velocity vector: x = {0}, y = {1}", velocity.X, velocity.Y);
}
Console.WriteLine("Iteration: {0}", i);
}
Console.ReadKey();
}
I traced the values in the CalculateNewVelocity function and noticed it all messes up on the 5th iteration. Infact, right when the new angle is calculated.
Here is my output:
http://i28.tinypic.com/2uii2pj.jpg
So I noticed the angle is already n. def. so I checked the function I use to calculate the angle, and this is the important part:
Quote:
public static double CalculateTheAngle(Vector2D vectA, Vector2D vectB)
{
double angleDeg;
double angleRad;
double x = (vectA * vectB) / (vectA.Length * vectB.Length);
Console.WriteLine(" Now in CalculateTheAngle function...");
// Make positive
if (x < 0)
x = x * (-1);
Console.WriteLine(" x which will be passed to cosine: x = {0}", x);
angleRad = Math.Acos(x);
Console.WriteLine(" angleRad = {0}", angleRad);
angleDeg = (angleRad * 180) / Math.PI;
Console.WriteLine(" angleDeg = {0}", angleDeg);
Console.WriteLine(" Returning back to CalculateNewVelocity function...");
return angleDeg;
}
As you can see, I put some Console statements in there too and noticed that the line "angleRad = Math.Acos(x);" (bold in the code) returns n. def. eventhough the value passed to it (x) is 1...as you can see in the picture with my output code.
To make along story short, why does this arc cos function fail to return a valid value? x is not greater or smaller than 1...so it should work.
Is this a problem in my floating point arithmetic? Will checking to see if x > 1 and setting it to 1 if it is, solve the problem in the best manner?
Any help would be great,
Chris