I l@ve RuBoard Previous Section Next Section

Modeling Gravity Effects

One of the most common effects that a game programmer needs to model in a game is that of gravity. Gravity is the force that attracts every object in the universe to every other. It is an invisible force and unlike magnetic fields can't be blocked.

In reality, gravity isn't really a force. That's simply how we perceive it. Gravity is caused by the curvature of space. When any object is positioned in space it creates a bending of the surrounding space, as shown in Figure 13.12. This bending creates a potential energy difference and hence any object near the gravity well "falls down" toward the object—weird, huh? That's really what gravity is. It's a manifestation of the bending of the space-time fabric.

Figure 13.12. Gravity and space-time.

graphics/13fig12.gif

You won't need to worry about space-time curvature and what gravity really is; you just want to model it. There are really two cases that you need to consider when modeling gravity, as shown in Figure 13.13:

  • Case 1: Two or more objects with relatively the same mass.

  • Case 2: Two objects where the mass of one object is much greater than the other.

Figure 13.13. The two general cases of gravity.

graphics/13fig13.gif

Case 2 is really a sub-case of Case 1. For example, in school you may have learned that if you drop a baseball and a refrigerator off a building they both fall at the same rate. The truth of the matter is they don't, but the difference is so infinitesimal (on the order 10-24) that you could never see the difference. Of course, there are other forces that might make a difference, like wind shear and friction, hence a baseball is going to fall faster than a piece of paper because the paper is going to feel a lot of wind resistance.

Now that you know a little bit about what gravity is, let's take a look at the math behind it. The gravitational force between any two objects with mass m1 and m2 is

F = G*m1*m2 / r2.

where G is the gravitational constant of the universe equal to 6.67x10-11 N*m2 * kg -2. Also, the masses must be in kilograms and the distance r in meters. Say that you want to find out what the gravitational attraction is between two average sized people of 70 kg (155 lbs.) at a distance of 1 meter:

F = 6.67x10-11*70kg*70kg/(1 m)2 = 3.26x10-7 N.

That's not much is it? However, let's try the same experiment with a person and the planet Earth at 1 meter given that the Earth has a mass of 5.98x1024 kg:

F = 6.67x10-11*70 kg*5.98x1024 kg/(1 m)2 = 2.79x1016 N.

Obviously, 1016 Newtons would crush you into a pancake, so you must be doing something wrong. The problem is that you're assuming that the Earth is a point mass that is 1.0 meters away. A better approximation would be to use the radius of the Earth (the center of mass) as the distance, which is 6.38x106 m:

MATH

You may assume that any spherical mass of radius r is a point mass as long as the matter the sphere is made of is homogenous and any calculations must place the other object at a distance greater than or equal to r.


F = 6.67x10-11 * 70 kg * 5.98x1024 kg / (6.38x106 m)2
  =  685.93 N.

Now that seems more reasonable. As a sanity check, on Earth 1 lb. is equal to 4.45 N, so converting the force to lbs. produces

685.93 N / (4.45 N / 1 lb.) = 155 lbs.

And this was the starting weight! Anyway, now that you know how to compute the force between two objects you can use this simple model in games. Or course, you don't have to use the real gravity constant G = 6.67x10-11, you can use whatever you like—remember, you are god. The only thing that's important is the form of the equation that states that the gravity between two objects is proportional—to a constant times the product of their masses divided by the distance squared between the objects' centers.

Modeling a Gravity Well

By using the formulation explained in the preceding section, you might, say, model a black hole in a space game. For example, you might have a ship that is flying around on the screen near a black hole, and want the ship to get sucked in if it gets too close. Using the gravitational equation is a snap. You would make up a constant G that worked well in the virtual game world (based on screen resolution, frame rate, etc.) and then simply set an arbitrary mass for the ship and one for the black hole that was much larger. Then you would figure out the force and convert the force to acceleration with F=m*a. You would simply vector or fly the ship directly toward the black hole each frame. As the ship got closer the force would increase until the player couldn't get free!

As an example of a black hole simulation (which is nothing more than two masses, one much larger than another) take a look at DEMO13_3.CPP|EXE (16-bit version, DEMO13_1_16B.CPP|EXE). It's a space simulator that allows you to navigate a ship around the screen, but there's a black hole in the middle that you have to deal with! Use the arrows keys to control the ship. Try to see if you can get into an orbit!

The next use of gravity in games is to simply make things fall from the sky or off buildings at the proper rate. This is really the special case that we talked about before, that is, one object has a mass much greater than the other. However, there's one more constraint and that is that one object is fixed—the ground. Take a look at Figure 13.14; it depicts the situation that I'm describing.

Figure 13.14. Gravitational attraction.

graphics/13fig14.gif

In this case, there are a number of assumptions that we can make that will make the math work out simpler. The first is that the acceleration due to gravity is constant for the mass that is being dropped, which is equal to 9.8 m/s2 or 32 ft/s2. Of course, this isn't really true, but is true to about 23 decimal places. If we know that the acceleration of any object is simply 9.8 m/s2 then we can just plug that into our old motion equation for velocity or position. Thus, the formula for velocity as a function of time with Earth gravity is

V(t) = v0 + 9.8 m/s2*t.

And position is

y(t) = y0 + v0*t + 1/2 * 9.8m/s2 * t2.

In the case of a ball falling off a building we can let the initial position x0 be equal to 0 and the initial velocity v0 also equal 0. This simplifies the falling object model to

y(t) = 1/2 * 9.8m/s2 * t2.

Furthermore, you are free to change the constant 9.8 to anything you like and t represents the frame number (virtual time) in a game. Taking all that into consideration, here's how you would make a ball fall from the top of the screen:

int y_pos      = 0, // top of screen
    y_velocity = 0, // initial y velocity
    gravity    = 1; // do want to fall too fast

// do  gravity loop until object hits
// bottom of screen at SCREEN_BOTTOM
while(y_pos < SCREEN_BOTTOM)
     {
     // update position
     y_pos+=y_velocity;

     // update velocity
     y_velocity+=gravity;
     }  // end while

TIP

I used the velocity to modify the position rather than modifying the position directly with the position formula. This is simpler.


You may be asking how to make the object fall with a curved trajectory. This is simple—just move the x position at a constant rate each cycle and the object will seem like it was thrown off rather then just dropped. The code to do this follows:

int y_pos      = 0, // top of screen
    y_velocity = 0, // initial y velocity
    x_velocity = 2, // constant x velocity
    gravity    = 1; // do want to fall too fast
// do  gravity loop until object hits
// bottom of screen at SCREEN_BOTTOM
while(y_pos < SCREEN_BOTTOM)
     {
     // update position
     x_pos+=x_velocity;
     y_pos+=y_velocity;
     // update velocity
     y_velocity+=gravity;
     }  // end while

Modeling Projectile Trajectories

Falling objects are fairly exciting, but let's see if we can do something a little more appropriate for video game programming! How about computing trajectory paths? Take a look at Figure 13.15, which shows the general setup for the problem. We have a ground plane, call it y=0, and a tank located at x=0, y=0, with a barrel pointed at an angle of inclination q (theta) with the x-axis. The question is, if we fire a projectile with mass m at a velocity vI, what will happen?

Figure 13.15. The trajectory problem.

graphics/13fig15.gif

We can solve the problem by breaking it up into its x,y components. First, let's break the velocity into an (x,y) vector:

Vix = V*cos q
Viy = V*sin q

Trust me.

Okay, now forget about the x part for a minute, and think about the problem. The projectile is going to go up and down and hit the ground. How long will this take? Take a look at our previous gravity equations:

V(t) = v0 + 9.8 m/s2*t.

The position for the y-axis is

y(t) = y0 + v0*t + 1/2 * 9.8m/s2 * t2.

The first one tells us the velocity relative to time. That's what we need. We know that when the projectile reaches its maximum height, the velocity will be equal to 0. Further-more, the amount of time that the projectile takes to reach this height will be the same amount of time it takes to fall to the ground again. Take a look at Figure 13.15. Plugging in our values for initial y velocity of our projectile and solving for time t, we have

Vy(t) = Viy - 9.8 m/s2*t

Note that I flipped the sign of the acceleration due to gravity because down is negative and matters in this case, and in general, when the velocity equals 0:

0 = V*sin q - a*t (a is just the acceleration)

Solving for time t, we get

t = Viy * (sin q)/a

Now the total time of flight is just time up + time down which equals t+t=2*t since the projectile must go up, then down. Therefore, we can revisit the x component now. We know that the total flight time is 2*t and we can compute t from (Viy * (sin q)/a). Therefore, the distance that the projectile travels in the x-axis is just

X(t) = vix*t

Plugging in our values, this results in

xhit = (V*cos q) * (V*(sin q)/a)

or

xhit = Vix * Viy/a

Neat, huh?

MATH

Note that I replaced the 9.8 value of acceleration with a. I did this to re-enforce that the acceleration is just a number, and you can make it whatever you wish.


That's the physics behind everything, but how do you model it in a program? Well, all you do is apply constant x-axis velocity to the projectile and gravity in the y-axis and test for when the projectile hits the ground or something else. Of course, in real life the X and Y velocities would diminish due to air resistance, but throwing that out the algorithm I just described works great. Here's the code to do it:

// Inputs
float x_pos      = 0, // starting point of projectile
      y_pos      = SCREEN_BOTTOM, // bottom of screen
      y_velocity = 0, // initial y velocity
      x_velocity = 0, // constant x velocity
      gravity    = 1, // do want to fall too fast
      velocity   = INITIAL_VEL, // whatever
      angle      = INITIAL_ANGLE; // whatever, must be in radians

// compute velocities in x,y
x_velocity = velocity*cos(angle);
y_velocity = velocity*sin(angle);


// do projectile loop until object hits
// bottom of screen at SCREEN_BOTTOM
while(y_pos < SCREEN_BOTTOM)
     {
     // update position
     x_pos+=x_velocity;
     y_pos+=y_velocity;

     // update velocity
     y_velocity+=gravity;
     }  // end while

That's all there is to it! If you want to add a wind force, just model it as a small acceleration in the direction opposing the X-motion, and assume that the wind force creates a constant acceleration against the projectile. As a result, you simply need to add this line of code in the projectile loop:

x_velocity-=wind_factor;

Where wind_factor would be something like 0.01—something fairly small.

As a demo of all this trajectory stuff, check out DEMO13_4.CPP|EXE (16-bit version, DEMO13_1_16B.CPP|EXE) on the CD. A screen shot is shown in Figure 13.16. The demo allows you to aim a virtual cannon and fire a projectile.

Figure 13.16. The projectile demo.

graphics/13fig16.gif

Here are the controls:

Key Action
Up, down Controls the angle of the tank's cannon.
Right, left Controls the velocity of the projectile.
G, B Controls the gravity.
W, E Controls the wind speed.
Ctrl Fires the cannon!

    I l@ve RuBoard Previous Section Next Section