Calculating the new direction after collision

Started by
8 comments, last by Floru 22 years, 7 months ago
Hi! I previously asked about collision detection with lines and circles and I got it work. Thanks for help! Now I''d like to know how should I calculate the new direction after a collision with line or circle? I have following variables for the objects: double dMovX; double dMovY; I made it work so that if the object hits something when going to right I just multiply the dMovX with -1 so that it changes direction etc. But it doesn''t look realistic with lines.Could someone tell how to do this? At most I''m intrested in collision with circles and lines. Floru
Advertisement
The way a collision causes an object to change it''s motion is through an impulse. This causes an instantaneous change in momentum, with the change given by the size and magnitude of the impulse. For a single moving object you can ignore the mass and work with velocity rather than momentum.

In practice this means you need to:
1) work out the direction of the collision. e.g. for a circle/ball hitting a line/surface without friction it will be the perpendicular/normal direction.
2) work out the impact speed, the speed in the direction of the collision, i.e. the speed towards the line/surface.
3) work out the impulse. If there''s no rotation it will be simply between 1 and 2 times the impact speed, with 1 being no bounce and 2 being maximum bounce. It is in the direction as the normal/perpendicular, away from the edge/surface.
4) Add it to the object velocity to get the velocity after the collision.

This is for an object hitting a fixed edge/surface, in 2D or 3D, ignoring friciton and rotation. These can be added in to the above proceedure but they make the calculations a lot more complex, especially in 3D.
John BlackburneProgrammer, The Pitbull Syndicate
You need to find the surface normal, which is pretty much a line at 90 degrees to the point at which you are colliding with. Then, the angle between the ball''s original vector and the ball''s new vector are equal, but on opposite sides of the normal.

Trying is the first step towards failure.
Trying is the first step towards failure.

Thanks! But could you please give some kind of example because I''m not so good at maths? If lines are described with two points (x1,y1 and x2,y2) and I know when for example that a ball hits the line. And I know what is ball''s direction. And there is no need to calculate friction and rotation.

Floru
One way is to reflect the component of the ball''s velocity in the direction of the normal to the line.

I.e:
Using (dMovX, dMovY) as the ball''s initial velocity, and points (x1,y1) and (x2,y2) as defining the line.

; Find line normal to line (as (nx, ny))
nx = y2 - y1 ; Find direction
ny = -(x2 - x1)
length = SquareRoot (nx*nx + ny*ny)
nx = nx / length ; Normalise (scale to length 1)
ny = ny / length
; Find component of ball''s velocity in direction of normal
dotProd = dMovX * nx + dMovY * ny
componentX = nx * dotProd
componentY = ny * dotProd
; Reflect this component of the ball''s velocity
newDMovX = dMovX - 2 * componentX
newDMovY = dMovY - 2 * componentY

This is off the top of my head, and hasn''t been tested.
I suggest looking up normals, vector normalization and dot product (or simply 2D vector arithmetic in general).
I have some code for calculation the new directions.


// vDelta = Distance between the two actors:
float fContactAngle,
fXClosingVelocity, fYClosingVelocity, fResVelocity, fXContactVelocity,
fYContactVelocity, fClosingAngle, fMassFactor, fMass1, fMass2, fAdiff, fPortion;

// Determine the angle of contact
if(vDelta.fX != 0)
{
fContactAngle = (float) atan(vDelta.fY/vDelta.fX);
if(fContactAngle < 0)
fContactAngle = -fContactAngle;
}
else
fContactAngle = (float) PId2;

// To determine how the objects will rebound off of each
// other, we are not concerned with the speed of each
// object, but rather the relative, or closing, speeds
// of the two objects.
fXClosingVelocity = pActor2->vWorldVelocity.fX-pActor1->vWorldVelocity.fX;
fYClosingVelocity = pActor2->vWorldVelocity.fY-pActor1->vWorldVelocity.fY;
// Calculate the x & y speed in the direction of contact
fResVelocity = ASFastSqrt(fXClosingVelocity*fXClosingVelocity+fYClosingVelocity*fYClosingVelocity);
fXContactVelocity = (float) cos(fContactAngle)*fResVelocity;
fYContactVelocity = (float) sin(fContactAngle)*fResVelocity;

// Now, determine the closing angle.
if(fXClosingVelocity != 0)
{
fClosingAngle = (float) atan(fYClosingVelocity/fXClosingVelocity);
if(fClosingAngle < 0)
fClosingAngle = -fClosingAngle;
}
else
fClosingAngle = (float) PId2;

// Hmmmm...
// With equal masses,
// the max rebound speed is 1/2 the closing speed.
// With unequal masses,
// the max rebound speed is the closing speed.
// Okay then,
// Normalize the two masses to be: mass1 + mass2 = 2.0
fMassFactor = 2/(pActor1->fMass+pActor2->fMass);
fMass1 = pActor1->fMass*fMassFactor;
fMass2 = pActor2->fMass*fMassFactor;

// Quadrant-specific stuff
if(pActor1->vWorldPos.fX > pActor2->vWorldPos.fX)
{
if(pActor1->vWorldPos.fY < pActor2->vWorldPos.fY)
{
// pActor1 is contacting upper right quadrant of pActor2
if(fYClosingVelocity < 0)
{
if(fXClosingVelocity < 0)
fAdiff = (float) PI-fContactAngle-fClosingAngle;
else
fAdiff = fContactAngle-fClosingAngle;
}
else
fAdiff = fContactAngle+fClosingAngle;
fPortion = (float) cos(fAdiff);
pActor1->vWorldVelocity.fX += fXContactVelocity*fPortion*fMass2;
pActor1->vWorldVelocity.fY -= fYContactVelocity*fPortion*fMass2;
pActor2->vWorldVelocity.fX -= fXContactVelocity*fPortion*fMass1;
pActor2->vWorldVelocity.fY += fYContactVelocity*fPortion*fMass1;
}
else
{
// pActor1 is contacting lower right quadrant of pActor2
if(fYClosingVelocity > 0)
{
if(fXClosingVelocity < 0)
fAdiff = (float) PI-fContactAngle-fClosingAngle;
else
fAdiff = fContactAngle-fClosingAngle;
}
else
fAdiff = fContactAngle+fClosingAngle;
fPortion = (float) cos(fAdiff);
pActor1->vWorldVelocity.fX += fXContactVelocity*fPortion*fMass2;
pActor1->vWorldVelocity.fY += fYContactVelocity*fPortion*fMass2;
pActor2->vWorldVelocity.fX -= fXContactVelocity*fPortion*fMass1;
pActor2->vWorldVelocity.fY -= fYContactVelocity*fPortion*fMass1;
}
}
else
{
if(pActor1->vWorldPos.fY < pActor2->vWorldPos.fY)
{
// pActor1 is contacting upper left quadrant of pActor2
if(fYClosingVelocity < 0)
{
if(fXClosingVelocity < 0)
fAdiff = fContactAngle-fClosingAngle;
else
fAdiff = (float) PI-fContactAngle-fClosingAngle;
}
else
fAdiff = fContactAngle+fClosingAngle;
fPortion = (float) cos(fAdiff);
pActor1->vWorldVelocity.fX -= fXContactVelocity*fPortion*fMass2;
pActor1->vWorldVelocity.fY -= fYContactVelocity*fPortion*fMass2;
pActor2->vWorldVelocity.fX += fXContactVelocity*fPortion*fMass1;
pActor2->vWorldVelocity.fY += fYContactVelocity*fPortion*fMass1;
}
else
{
// pActor1 is contacting lower left quadrant of pActor2
if(fYClosingVelocity > 0)
{
if(fXClosingVelocity < 0)
fAdiff = fContactAngle-fClosingAngle;
else
fAdiff = (float) PI-fContactAngle-fClosingAngle;
}
else
fAdiff = fContactAngle+fClosingAngle;
fPortion = (float) cos(fAdiff);
pActor1->vWorldVelocity.fX -= fXContactVelocity*fPortion*fMass2;
pActor1->vWorldVelocity.fY += fYContactVelocity*fPortion*fMass2;
pActor2->vWorldVelocity.fX += fXContactVelocity*fPortion*fMass1;
pActor2->vWorldVelocity.fY -= fYContactVelocity*fPortion*fMass1;
}
}



At the moment it only works for 2D. Could someone help me to add the third dimension??
A realy simple technique,
which looks pretty good is to swap the velocity vectors of the colliding bodies.

//store the velocity of the first body in a seperate variable
velocity_body1 = intermediate_storage;

//set velocity body 1 = velocity of body 2
velocity_body1 = velocity_body2;

//set velocity of body 2 = velocity body 1 original value
velocity_body2 = intermediate_storage;

and you''ve swapped there velocity vectors!!
its not physically perfect, but its simple ao give it a shot

Thanks for help!

I have now a working collision detection and I also know how to calculate new direction. I have a problem and I don''t know how common it is. I''ve seen demos where balls bounce in box or in area but sometimes the balls don''t work correctly. For example they stick into walls or go through them or bounce funny. I have same kind on problems. Rarely but I''d like to my system work perfectly. I also have a object which is controlled by the user (like in pinball game the flipper). But usually the balls go through. So how can I make my system perfect? Is this a common problem?

Floru
I think the sticking-together problem is caused by the fact, that you only do coll-detection in finite time steps, i.e. you can only detect collisions if objects stick together already.
(Also if sometimes only a little bit)
I''ve had and still have some problems with that penetration problem, but you can solve it.
Try to find out "how much" the one object is inside the other one and then move your object away along the collision normal by your measured penetration. This will create a non-penetration state of the bodies.

A little bit hard to explain, but perhaps have a look into the FastCar source code.
http://www.oxforddynamics.co.uk

Ciao!
Roppi

http://www.moonbyte.de

Thanks for the link but the documentation was quite complicated although the demo was quite impressive. Is there any simpler sample or documentation? I think some info how flipper games are made could also be useful. What about the sticking problem?

Floru

This topic is closed to new replies.

Advertisement