   Conserving Energy
  Hello, I am working on a simple 2D physics program involving lots of planets that are attracted to each other by the force of gravity and bounce off when they get close enough. After a lot of work I finally got them to collide properly, but unfortunately, they seem to gain energy after every collision. For example, placing two of them in the center of the screen, they bounce farther and farther away from each other. Could somebody highlight an error in my source or give me some pseudocode that will help correct this? Here is the rendering function:  void RenderObjects(double oldTime, double currentTime, sObject* headObject){double timeSincePreviousFrame = currentTime - oldTime;for(sObject* Object = headObject; Object != NULL; Object = Object->nextObject){Object->oldX= Object->X;Object->oldY= Object->Y;Object->oldVx= Object->Vx;Object->oldVy= Object->Vy;Object->oldAx= Object->Ax;Object->oldAy= Object->Ay;double g(0);double gX(0);double gY(0);for(sObject* Object2 = headObject; Object2 != NULL; Object2 = Object2->nextObject){if((Object->X != Object2->X)||(Object->Y != Object2->Y)) //to ensure no divide by 0{double d = Distance(Object->X, Object->Y, Object2->X, Object2->Y);g = Object2->mass / (d * d); //Gets the angle they make with the X axisdouble angle = Angle(Object->X, Object->Y, Object2->X, Object2->Y);gX += g * cos(angle * PI / 180);gY += g * sin(angle * PI / 180);}}//Yes, I know I could have combined these loops, but my goal now is to get this//to work. Then I make it fast.bool collision(false);double velocityA(0);double velocityB(0);double newV(0);double newVx(0);double newVy(0);const double restitution(1);for(sObject* Object2 = headObject; Object2 != NULL; Object2 = Object2->nextObject){if((Object->X != Object2->X)&&(Object->Y != Object2->Y)){if(Distance(Object->X,Object->Y,Object2->X,Object2->Y) <= 60) // This twice the radius of the balls.    //If the distance is less than 60 they are touching.{collision = true;velocityA = sqrt((Object->Vx * Object->Vx) + (Object->Vy * Object->Vy));velocityB = sqrt((Object2->Vx * Object2->Vx) + (Object2->Vy * Object2->Vy));double angle = Angle(Object->X, Object->Y, Object2->X, Object2->Y);//This formula is very probably wrong or could be betternewV = -((Object->mass * velocityA) + (Object2->mass * velocityB) - Object->mass * restitution * (velocityA - velocityB)) / (Object->mass + Object2->mass );newVx = newV * cos(angle * PI / 180);newVy = newV * sin(angle * PI / 180);}}}Object->Ax = gX;Object->Ay = gY;if(collision == true){Object->Vx = newVx;Object->Vy = newVy;}else{Object->Vx = Object->Ax * timeSincePreviousFrame + Object->oldVx;Object->Vy = Object->Ay * timeSincePreviousFrame + Object->oldVy;}Object->X = Object->oldX + Object->oldVx * timeSincePreviousFrame +((Object->Ax * timeSincePreviousFrame * timeSincePreviousFrame) / 2);Object->Y = Object->oldY + Object->oldVy * timeSincePreviousFrame +((Object->Ay * timeSincePreviousFrame * timeSincePreviousFrame) / 2);Object->Draw();}}Thanks![edited by - sAlFace on February 9, 2004 8:19:06 PM]
  Do you have a bounce value?if his 1, the size of your vector after will be the same as before the collision.If the bounce value is .5, the planets will be 2 times slower after. ;  I once did something like this and had the same sort of thing happen. I think the problem may be from the explicit numerical integration. When the planets are moving away from each other, they are accelerating at a constant speed over each time step, while physically that acceleration could be decreasing quite rapidly over the time step.Try doing this: add half of the acceleration to the velocity before updating the position, then recalculate the acceleration in the new position and add half of this new acceleration to the velocity. Equivalently you can keep track of the velocity at times offset by half a timestep from the position. ;  If it''s just that the particles gain too much energy during the collision and bounce "too hard", check that the collision isn''t performed more than once. This can occur if the particles intersect and still intersect the next loop round so the collision is performed again. 