Gravity Gun

From ODE
Jump to: navigation, search

A "gravity gun", made famous by Valve's "Half-Life 2", is a gameplay feature that demonstrates the great scope for immersion provided by in-game physics. A similar effect can also be found in several other games, including Pandemic's Destroy All Humans, where different tuning has allowed for a more drifting motion.

Gravity Gun

  • Handle your character moving around the world as normal, I used a sphere to begin with, but moved onto a capsule - it really doesn't matter. So long as you have a world divided into static entities that are the world, and dynamic entities that can move around and have an ODE body attached.
  • Handle player input to activate the gravity gun by creating a dRay which starts at the centre of the player (probably offset slightly to more accurately position it at the gun barrel) and extends in the direction of aiming for a number of units.
  • In your collision callback you need to treat ray / geom collisions as a special case, that is instead of the usual contact joint creation to get solid objects colliding you should detect if "dGeomGetClass( geom ) == dRayClass" and handle it differently. For this application you want to find the 'nearest colliding body which isn't the player' which will be the target for your gravity gun. The usual call to dCollide will return a number of collisions for the ray, in this case contact 'depth' field actually indicates the distance along the ray to the target. Ignoring the player's geom will allow you to get the nearest thing you're trying to grab with the gun simply using MIN. I'd recommend looking into the dGeomGetData call so that you can associate a game specific structure to the objects you want to interact with - in my engine if that data is NULL then the geom is part of the world and will be ignored.
  • After the collision checking has completed (don't forget to remove the ray from the collision space), you should have the geom id for the entity you want to pick up. Keep hold of this in your player structure because you'll need it until you release the object.
  • By default gravity will still affect the object during capture - this isn't helpful as you want total control over the forces, and it is a 'Gravity Gun' effect after all, so simply call dBodySetGravityMode to disable the influence of gravity on the object during capture.
  • In your player update code, you need to have the targets body, position, the camera position and the camera direction. Here is a code fragment how to implement the update code:
 if ( GravityGunEnabled )
 {
   // You have to experiment with these three values:

   float powerfactor = ?; // Higher values causes the targets moving faster to the holding point.
   float maxVel = ?;      // Lower values prevent objects flying through walls.
   float fdistance = ?;   // Should big enough, that the biggest item to hold doesn't collide with the player.

   holdpos = CameraPosition + CameraDir * fdistance; // fdistance in front of the player is the Holdpoint

   v = holdpos - TargetPosition; // direction to move the Target
   v *= powerfactor; // powerfactor of the GravityGun

   if ( sqrt( v.x * v.x + v.y * v.y + v.z * v.z ) > maxVel )
   {
     // if the correction-velocity is bigger than maximum
     D3DXVec3Normalize(&v, &v);
     v *= maxVel; // just set correction-velocity to the maximum
   }

   dBodyEnable( TargetBody );
   dBodySetLinearVel( TargetBody, v.x, v.y, v.z );
 }
  • If the gravitygun is deactivated, you should turn on gravity for the object and forget the targetbody.

Additional Notes

  • You should deactivate the gravitygun if the object is to far away, or if the object is behind the player. This looks natural, like a operation-angle/range of the weapon.
  • You can recreate the 'drop' and 'kick' features by simply stopping the application of the correcting force and reenabling gravity or you finish with a single large force along the aiming direction vector respectively. This is a great gameplay feature and looks really cool!
  • In Destroy All Humans you can dynamically adjust the 'capture distance', to do this you simply need to find suitable minimum and maximum ranges to match the particular environment as it's not really any different to walking forward or back.
  • The held object will rotate freely in mid-air, if you do not require this behaviour apply some damping to the angular velocity.