Выбрать главу

The first line below creates a structure for our player. Basically we're giving our player structure fx, fy, x, y and spin values. By adding this line, we can access the player x position by checking player.x. We can change the player spin by adding a number to player.spin.

The second line is a bit different. Because we can have up to 15 enemies on the screen at a time, we need to create the above variables for each enemy. We do this by making an array of 15 enemies. the x position of the first enemy will be enemy[0].x. The second enemy will be enemy[1].x, etc.

The last line creates a structure for our special item. The special item is an hourglass that will appear on the screen from time to time. We need to keep track of the x and y values for the hourglass, but because the hourglass doesn't move, we don't need to keep track of the fine positions. Instead we will use the fine variables (fx and fy) for other things later in the program.

struct object player; // Player Information

struct object enemy[9]; // Enemy Information

struct object hourglass; // Hourglass Information

Now we create a timer structure. We create a structure so that it's easier to keep track of timer variables and so that it's easier to tell that the variable is a timer variable.

The first thing we do is create a 64 bit integer called frequency. This variable will hold the frequency of the timer. When I first wrote this program, I forgot to include this variable. I didn't realize that the frequency on one machine may not match the frequency on another. Big mistake on my part! The code ran fine on the 3 systems in my house, but when I tested it on a friends machine the game ran WAY to fast. Frequency is basically how fast the clock is updated. Good thing to keep track of :)

The resolution variable keeps track of the steps it takes before we get 1 millisecond of time.

mm_timer_start and mm_timer_elapsed hold the value that the timer started at, and the amount of time that has elapsed since the the timer was started. These two variables are only used if the computer doesn't have a performance counter. In that case we end up using the less accurate multimedia timer, which is still not to bad for a non-time critical game like this.

The variable performance_timer can be either TRUE of FALSE. If the program detects a performance counter, the variable performance_timer variable is set to TRUE, and all timing is done using the performance counter (alot more accurate than the multimedia timer). If a performance counter is not found, performance_timer is set to FALSE and the multimedia timer is used for timing.

The last 2 variables are 64 bit integer variables that hold the start time of the performance counter and the amount of time that has elapsed since the performance counter was started.

The name of this structure is "timer" as you can see at the bottom of the structure. If we want to know the timer frequency we can now check timer.frequency. Nice!

struct // Create A Structure For The Timer Information

{

 __int64 frequency; // Timer Frequency

 float resolution; // Timer Resolution

 unsigned long mm_timer_start; // Multimedia Timer Start Value

 unsigned long mm_timer_elapsed; // Multimedia Timer Elapsed Time

 bool performance_timer; // Using The Performance Timer?

 __int64 performance_timer_start; // Performance Timer Start Value

 __int64 performance_timer_elapsed; // Performance Timer Elapsed Time

} timer; // Structure Is Named timer

The next line of code is our speed table. The objects in the game will move at a different rate depending on the value of adjust. If adjust is 0 the objects will move one pixel at a time. If the value of adjust is 5, the objects will move 20 pixels at a time. So by increasing the value of adjust the speed of the objects will increase, making the game run faster on slow computers. The higher adjust is however, the choppier the game will play.

Basically steps[ ] is just a look-up table. If adjust was 3, we would look at the number stored at location 3 in steps[ ]. Location 0 holds the value 1, location 1 holds the value 2, location 2 holds the value 4, and location 3 hold the value 5. If adjust was 3, our objects would move 5 pixels at a time. Make sense?

int steps[6]={ 1, 2, 4, 5, 10, 20 }; // Stepping Values For Slow Video Adjustment

Next we make room for two textures. We'll load a background scene, and a bitmap font texture. Then we set up a base variable so we can keep track of our font display list just like we did in the other font tutorials. Finally we declare WndProc().

GLuint texture[2]; // Font Texture Storage Space

GLuint base; // Base Display List For The Font

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc

Now for the fun stuff :) The next section of code initializes our timer. It will check the computer to see if a performance counter is available (very accurate counter). If we don't have a performance counter the computer will use the multimedia timer. This code should be portable from what I'm told.

We start off by clearing all the timer variables to zero. This will set all the variables in our timer structure to zero. After that, we check to see if there is NOT a performance counter. The ! means NOT. If there is, the frequency will be stored in timer.frequency.

If there was no performance counter, the code in between the { }'s is run. The first line sets the variable timer.performance_timer to FALSE. This tells our program that there is no performance counter. The second line gets our starting multimedia timer value from timeGetTime(). We set the timer.resolution to 0.001f, and the timer.frequency to 1000. Because no time has elapsed yet, we make the elapsed time equal the start time.

void TimerInit(void) // Initialize Our Timer (Get It Ready)

{

 memset(&timer, 0, sizeof(timer)); // Clear Our Timer Structure

 // Check To See If A Performance Counter Is Available

 // If One Is Available The Timer Frequency Will Be Updated

 if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency)) {

  // No Performace Counter Available

  timer.performance_timer = FALSE; // Set Performance Timer To FALSE

  timer.mm_timer_start = timeGetTime(); // Use timeGetTime() To Get Current Time

  timer.resolution = 1.0f/1000.0f; // Set Our Timer Resolution To .001f

  timer.frequency = 1000; // Set Our Timer Frequency To 1000

  timer.mm_timer_elapsed = timer.mm_timer_start; // Set The Elapsed Time To The Current Time

 }

If there is a performance counter, the following code is run instead. The first line grabs the current starting value of the performance counter, and stores it in timer.performance_timer_start. Then we set timer.performance_timer to TRUE so that our program knows there is a performance counter available. After that we calculate the timer resolution by using the frequency that we got when we checked for a performance counter in the code above. We divide 1 by the frequency to get the resolution. The last thing we do is make the elapsed time the same as the starting time.

Notice instead of sharing variables for the performance and multimedia timer start and elapsed variables, I've decided to make seperate variables. Either way it will work fine.

 else {

  // Performance Counter Is Available, Use It Instead Of The Multimedia Timer