JavaScript EditorFree JavaScript Editor     Ajax Editor 

Main Page
  Previous Section Next Section

Playing God: Constructing Physics Models for Games

This chapter has given you a lot of information and concepts to sift through. The key is to use the concepts and some of the hard math to make working models that look good. No one will ever know if they accurately simulate reality 100 percent, nor will they care. If you can make an approximation then do it—as long as it's worth it. For example, if you're trying to make a racing game and you want to race on road, ice, and dirt, then you better have some frictional effects, otherwise, your cars will drive like they're on rails!

On the other hand, if you have an asteroid field that the player blows up and each asteroid splits into two or more smaller asteroids then I don't think the player is going to care or know for that matter the exact trajectory that the smaller asteroids would take—just pick them in a deterministic way so they look good.

Data Structures for Physics Modeling

One of the questions that I'm asked continuously (in addition to how to compile DirectX programs with VC++) is what data structures to use for physics modeling. There are no physics-data structures! Most physics models are based on the game objects themselves—you simply need to add enough data elements to your primary data structures to figure the physics out—get it? Nonetheless, you should keep track of the following parameters and values in any physics engine for the universe and objects:

  • Position and velocity of the object.

  • Angular velocity of the object.

  • Mass, frictional coefficient, and any other physical properties of the object.

  • Physics engine geometry for the object. This is simply a geometry that can be used for the physics calculations. You may use rectangles, spheres, or whatever, rather than the actual object geometry.

  • External universal forces such as wind, gravity, and so on.

Now it's up to you to represent all these values with whatever structures or types are appropriate. For example, the realistic collision response demo used a model something like this:

Each Ball Object

float x,y; // position
float xv,yv; // velocity
float radius; // guess?
float coefficient_of_restitution; // just what it says

Of course the data was hidden a little in some internal arrays in each of the BOBs (blitter objects) that represented the balls, but the abstract data structure is what we're interested in.

Frame-Based Versus Time-Based Modeling

This is the final topic I want to talk about since it's becoming more and more important in 3D games. Thus far in the book, we have had a game loop that looks like Figure 13.44. We have been assuming that the game will run at a constant rate of R fps. If it doesn't, then no big deal, everything will slow down on the screen. But what if you didn't want things to slow down on the screen? What if you wanted a ship to move from a to b in two seconds no matter what the frame rate was? This is called time-based modeling.

Figure 13.44. The game loop you've learned to love.


Time-based modeling differs from frame-based modeling in that time t is used in all the kinematic equations that move objects. For example, in a frame-based game if you have the chunk of code:

x = 0, y = 0;

x = x + dx;
y = y + dy;

and the game runs at 30 fps, then in 30 frames or 1 second, x,y will equal

x = 30*dx;
y = 30*dy;

If dx=1 and dy=0 then the object would move exactly 30 pixels in the x-direction. And this is fine if you can always guarantee a constant frame rate. But what if the frame rate drops to 10 fps? Then in 1 second, you will have

x = 10*dx = 10
y = 10*dy = 0

x only changed one-third of what you wanted it to! If visual continuity is what you are going for then this is unacceptable. In addition, this can wreak havoc on a network game. In a network game you can either sync to the slowest machine and stay frame-based, or you can let all the machines run free and use time modeling, which is the more realistic and fair thing to do. I shouldn't have to pay for someone else owning a 486 when I have a PIV 2.4GHz.

To implement time-based motion and kinematics, you have to use time in all of your motion equations. Then, when it's time to move objects, you have to test the difference in time from the last movement and use this as the input into your equations. Thus, as the game slows down a lot, it won't matter because the time parameter will convey this and cause a larger motion. Here's an example game loop:

t0 = Get_Time(); // assume this is in milliseconds

// work, work, work

// move objects
t1 = Get_Time();

// move all the objects
Move_Objects(t1 – t0);

// render

}  // end while

With this loop we use the change in time or (t1-t0) as an input to the motion code. Normally there would be no input; the motion code would just move. Let's assume that we want our object to move at 30 pixels per second, but since our time base is in milliseconds, or 1x10-3 seconds, we need to scale this:

dx = 30 pixels/1 sec = .03 pixels/1 millisecond

Can you see where I'm going? Let's write the motion equation for x:

x = x + dx*t

Plugging everything in we get

x = x +.03*(t1 – t0)

That's it. If a single frame takes one second then (t1 – t0) will be 1000 milliseconds and the motion equation will equal

x = x + .03*1000 = 30, which is correct!

On the other hand, if the time for this frame takes three milliseconds then the motion equation will look like

x = x + .03*3 = .09, which is also correct!

Obviously you need to use floating-point values for all this to work since you are going to be tracking fractions of pixel motion, but you get the idea. This is so cool because even if your game starts bogging down hardcore due to rendering, the motion will stay the same.

As an example, check out DEMO13_11.CPP|EXE (16-bit version, DEMO13_11_16B.CPP|EXE); it basically moves a little ship (with a shadow!) from left to right and allows you to alter the delay of each frame using the arrow keys to simulate processor load.

Notice that the ship moves at a constant rate. It may jump, but it will always travel a total distance of 50 pixels/sec no matter what the frame rate. As a test, the screen is 640 pixels wide, plus the off-screen overlap of 160 pixels, thus the entire travel is 800 pixels. Since the ship is traveling at 50 pixels/sec that means that it should take 800/50=16 seconds to make one pass. Try changing the delay and note that this is always true. If your game was designed to run at 60 fps and it slows to 15–30 then the jumping won't be that apparent and the game will look the same, but less smooth. Without time modeling your game WILL slow down and look like it's in slow motion—I'm sure you have seen this many times. :)

      Previous Section Next Section

    JavaScript EditorAjax Editor     JavaScript Editor