Game Development Community

Vehicle physics bug (vehicle sticking to terrain or objects)

by Vis · in Torque Game Engine · 07/12/2007 (10:25 am) · 8 replies

If a flyingVehical ever comes to rest ..... by removing the hover code or flying into another object slowly, the vehicle will stop and not move again, irrespective of user input.

The problem resides in Vehicle::updatePos()

....
....

      if (!mRigid.atRest) {

      collided = updateCollision(dt);
 
      // Now that all the forces have been processed, lets
      // see if we're at rest.  Basically, if the kinetic energy of
      // the vehicles is less than some percentage of the energy added
      // by gravity for a short period, we're considered at rest.
      // This should really be part of the rigid class...
      if (mCollisionList.count) {
         F32 k = mRigid.getKineticEnergy();
         F32 G = sVehicleGravity * dt;
         F32 Kg = 0.5 * mRigid.mass * G * G;
         if (k < sRestTol * Kg && ++restCount > sRestCount)
         		 mRigid.setAtRest(); 
      }
      else
         restCount = 0;
   }
   
    if (!mRigid.atRest)
        mRigid.integrate(dt);

.....
.....

Once mRigid.atRest has been set, no new changes to mRigid.force or mRigid.torque will be applied by mRigid.integrate();

Theres a bunch of ways this could be fixed, I did it this way:

On a clean TGE install version 1.52

I added a flag to the Vehicle class (vehicle.h line 170 : bool mUserInput;)
initialized it to false in the constructor (vehicle.cc line 466 mUserInput = false;)

added a test at the top of Vehicle::updateMove() to set the flag if there is any user input to move the vehicle:
if(move->x || move->y || move->z || move->roll || move->pitch || move->yaw)
    mUserInput = true;

then changed vehicle.cc at line 963 from

// Integrate forward
   if (!mRigid.atRest)
      mRigid.integrate(dt);

to ....

// Integrate forward
   if (!mRigid.atRest [b]|| mUserInput[/b])
   {
     mRigid.integrate(dt);
     mUserInput = false;
   }

I am a relatively inexperienced programmer so there's probably a much more elegant way to do this.

(EDIT: just realized theres an SDK bugs forum - sorry !)

#1
09/03/2007 (3:52 am)
Vis, other than setting your mUserInput flag at these two locations, what else does this do?

It seems to be incomplete.
#2
09/04/2007 (2:54 pm)
Yeah, I think that this line:
if (!mRigid.atRest)

Should be like this:
if (!mRigid.atRest || mUserInput)

Otherwise, good catch. I've seen that happen myself, but assumed it was part of the larger vehicle collision bug (where you get a freeze sometimes).
#3
09/08/2007 (4:49 am)
@ Ron ... its is .... it was a long day ! ....

and thanks Brian for fixing it

( I have corrected the original post )
#4
10/03/2007 (9:22 am)
Fantastic fix, works bloody awesome. Thanks.
#5
12/26/2009 (3:57 pm)
I changed this line
if(move->x || move->y || move->z || move->roll || move->pitch || move->yaw)  
     mUserInput = true;

to this

mUserInput = (move->x || move->y || move->z || move->roll || move->pitch || move->yaw)
#6
12/27/2009 (12:18 am)
@thomas

even though my programming is limited wouldnt that make mUserInput equal to the integer value of one of those instead of true?
#7
12/27/2009 (7:53 am)
@Scooby,

The point to get here is that 'true' is represented by any value other than zero.

I prefer to use an if statement for no other reason than readability, both will provide the same result.
#8
12/27/2009 (8:26 am)
(move->x || move->y || move->z || move->roll || move->pitch || move->yaw)
Evaluates as
((move->x != 0) || (move->y != 0) || ... etc etc
If I'm not mistaken.