Tricks of the Windows Game Programming Gurus:Vector Rasterization and 2D Transformations

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

### More on Timing and Synchronization

In most of the programs thus far, I’ve been using a very cheesy timing system—`Sleep()`. That’s about as low-tech as you can get <BG>. In real life, you need to lock your game to some frame rate, such as 30fps. A better way to achieve this lock is to start a timer at the top of the game loop (or take note of the current time) and then, at the end of the game loop, test if the amount of time for 30 fps—that is, 1/30 seconds—has elapsed. If so, continue to the next frame. If not, wait until the time has elapsed (maybe work on the next frame or do some housekeeping so as not to waste cycles).

In computer code, you would structure your `Game_Main()` something like this:

    DWORD Get_Clock(void);

    DWORD Start_Clock(void);

    DWORD Wait_Clock(DWORD count);

    int Game_Main(void *parms = NULL, int num_parms = 0)

    {

    // this is called each frame

    // get the current time in milliseconds since windows

    // was started

    Get_Clock();

    // do work…

    // sync to frame rate, 30 fps in this case

    Wait_Clock(30);

    } // end Game_Main

Simple as that! Oh yeah… what about these phantom functions? Ahhh yes, here they are—based on Win32 timing functions:

    DWORD Get_Clock(void)

    {

    // this function returns the current tick count

    // return time

    return(GetTickCount());

    } // end Get_Clock

    ///////////////////////////////////////////////////////////

    DWORD Start_Clock(void)

    {

    // this function starts the clock, that is, saves the current

    // count, use in conjunction with Wait_Clock()

    return(start_clock_count = Get_Clock());

    } // end Start_Clock

    ////////////////////////////////////////////////////////////

    DWORD Wait_Clock(DWORD count)

    {

    // this function is used to wait for a specific number of clicks

    // since the call to Start_Clock

    while((Get_Clock() - start_clock_count) < count);

    return(Get_Clock());

    } // end Wait_Clock

C++ This is a perfect place for a C++ class; feel free.

Notice that they’re based on the Win32 function `GetTickCount()`, which returns a `DWORD` equal to the number of milliseconds elapsed since Windows was started. Hence, the time is relative, but who cares? That’s all you need. Also, notice the use of the global `start_clock_count` to store the starting time. It’s set every time `Get_Clock()` is called and is defined like this in the library:

    DWORD start_clock_count = 0;     // used for timing

DirectX also has a vertical blank detection function that you can use to determine the state of the electron gun as it renders the image on the CRT. The `IDIRECTDRAW4` interface supports a function called `WaitForVerticalBlank()`, as shown here:

    HRESULT WaitForVerticalBlank(DWORD dwFlags,

                                 HANDLE hEvent);

You can use it to determine the various states of the vertical blank. `dwFlags` controls the operation of the function, and `hEvent` is a handle to a Win32 event (advanced stuff). Take a look at Table 8.3 for the valid flag settings.

Table 8.3 Flag Settings for `WaitForVerticalBlank()`

Flag | Description
--- | ---

`DDWAITVB_BLOCKBEGIN` | Returns when the vertical-blank interval begins.
`DDWAITVB_BLOCKEND` | Returns when the vertical-blank interval ends and the display begins.

### Scrolling and Panning

All right, I guess that I think scrolling is easy because I never really put it in my books. (But in my defense, I did put page scrolling in Sams Teach Yourself Game Programming in 21 Days, and I put full layered and playfield scrolling in The Black Art of 3D Game Programming.) Scrolling games are in a class all their own, and really explaining all the 2D scrolling techniques would take a good chapter or two. Instead, I want to talk to you in a more abstract way about each scrolling method and then show you some demos.

#### Page Scrolling Engines

Page scrolling basically means that as the player moves around on the screen and crosses some threshold, the entire screen is updated as if the player has walked into another room. This technique is very easy to implement and can be coded in a number of ways. Referring to Figure 8.43, you see a typical game universe consisting of a 4×2 matrix of full screens at 640×480 pixels each. Hence, the entire universe is 2560×960.

Figure 8.43 A page scrolling universe setup.

The rendering logic is simple for this setup. You load the first screen into memory, and then you can load all adjacent screens into RAM or virtualize them on disk. Either way you do it, the scrolling works the same. As the player’s character moves around the screen, you test it for some boundary condition (maybe the screen edges). When the boundary condition is met, you advance to the next “room” or screen and move the player’s character to the appropriate position. For example, if you were walking from left to right and you hit the right edge of the screen, the new page would be displayed with the character at the left side of the screen. Of course, this is a bit crude, but it’s a start…

For a demo of this technique, take a look at `DEMO8_10.EXE|CPP` on the CD. It basically creates a 3×1 universe and lets you move a little character around with the arrow keys. When you hit a screen edge, the image is updated. Note that I’m using bitmaps for the screen images, but there’s no reason why you couldn’t use vector images or a mixture.

Also, I’m cheating a little on this demo by using functions from the final `T3DLIB1.CPP` file at the end of this chapter, but you can always look at the source if you want to. I simply needed more power than what we have so far to make a decent demo!

Finally, make sure to take a look at the “terrain following” code in the demo. The character follows the floor as you move right to left by scanning for a specific color index representing the floor (116, I think). When the scanner detects the color, the character is pushed up a little, keeping it above the floor line.

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.