JavaScript EditorFree JavaScript Editor     Ajax Editor 



Main Page
  Previous Section Next Section

The T3D Game Console

In the beginning of the book I mentioned that Win32/DirectX programming is almost like 32-bit DOS programming if you create a shell Windows application and then create a code structure that hides the details of the dull Windows stuff that's going on. Now you know enough to do this. In this section you'll see how to put together the T3D Game Console, which will be the basis for all the demos and games from here on.

At this point, you know that to create a Windows application you need a WinProc() and a WinMain() and that's about it. So we'll create a minimal Windows application that has these components and create a generic window. The application will then call out to three functions that perform the game logic. As a result, the details of handling Windows messages and other Win32-related drama won't be an issue (unless of course you want it to be). Take a look at Figure 4.14 to see the T3D Game Console architecture.

Figure 4.14. The architecture of the T3D Game Console.

graphics/04fig14.gif

As you can see, there are only three functions that are needed to implement the console:

int Game_Init(void *parms = NULL, int num_parms = 0);

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

int Game_Shutdown(void *parms = NULL, int num_parms = 0);
  • Game_Init() is called before the main event loop in WinMain() is entered and is called only once. Here is where you'll initialize everything for your game.

  • Game_Main() is like main() in a normal C/C++ program except that it is called each cycle after any Windows message handling is performed by the main event loop. This is where the entire logic of your game will be. You'll do all the rendering, sound, AI, and so forth in Game_Main() or as calls out of Game_Main(). The only caveat about Game_Main() is that you must draw only one frame and then return, so you don't starve the WinMain() event handler. Also, because this function is entered and exited each cycle, remember that automatic variables are transient—if you want data to stick around, make it global or local static to Game_Main().

  • Game_Shutdown() is called after the main event loop in WinMain() is exited, which is caused by a message sent from the user, ultimately causing a WM_QUIT message to be posted. In Game_Shutdown() you'll do all your housekeeping and cleanup of resources allocated during game play.

The T3D Game Console is contained in the file T3DCONSOLE.CPP. Below is the WinMain() section showing the calls to all the console functions:

// WINMAIN ////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hinstance,
            HINSTANCE hprevinstance,
            LPSTR lpcmdline,
            int ncmdshow)
{

WNDCLASSEX winclass; // this holds the class we create
HWND       hwnd;     // generic window handle
MSG          msg;      // generic message
HDC          hdc;      // graphics device context

// first fill in the window class structure
winclass.cbSize         = sizeof(WNDCLASSEX);
winclass.style            = CS_DBLCLKS | CS_OWNDC |
                                    CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc    = WindowProc;
winclass.cbClsExtra       = 0;
winclass.cbWndExtra      = 0;
winclass.hInstance     = hinstance;
winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground    = GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName    = NULL;
winclass.lpszClassName    = WINDOW_CLASS_NAME;
winclass.hIconSm              = LoadIcon(NULL, IDI_APPLICATION);

// save hinstance in global
hinstance_app = hinstance;
// register the window class
if (!RegisterClassEx(&winclass))
    return(0);

// create the window
if (!(hwnd = CreateWindowEx(NULL,                  // extended style
                            WINDOW_CLASS_NAME,     // class
                           "T3D Game Console Version 1.0", // title
                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                           0,0,           // initial x,y
                           400,300,   // initial width, height
                           NULL,       // handle to parent
                           NULL,       // handle to menu
                           hinstance, // instance of this application
                           NULL)))    // extra creation parms
return(0);

// save main window handle
HWND main_window_handle = hwnd;

// initialize game here
Game_Init();

// enter main event loop
while(TRUE)
    {
    // test if there is a message in queue, if so get it
    if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
       {
       // test if this is a quit
       if (msg.message == WM_QUIT)
           break;

       // translate any accelerator keys
       TranslateMessage(&msg);

       // send the message to the window proc
       DispatchMessage(&msg);
       } // end if

       // main game processing goes here
       Game_Main();

    } // end while

// closedown game here
Game_Shutdown();

// return to Windows like this
return(msg.wParam);

} // end WinMain

Take a moment or two and review the WinMain(). It should look very generic because it's the one we have been using all along! The only differences, of course, are the calls to Game_Init(), Game_Main(), and Game_Shutdown(), which follow:

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

int Game_Main(void *parms = NULL)
{
// this is the main loop of the game, do all your processing
// here

// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE))
   SendMessage(main_window_handle,WM_CLOSE,0,0);

// return success or failure or your own return code here
return(1);

} // end Game_Main

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

int Game_Init(void *parms = NULL)
{
// this is called once after the initial window is created and
// before the main event loop is entered; do all your initialization
// here


// return success or failure or your own return code here
return(1);

} // end Game_Init

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

int Game_Shutdown(void *parms = NULL)
{
// this is called after the game is exited and the main event
// loop while is exited; do all you cleanup and shutdown here


// return success or failure or your own return code here
return(1);

} // end Game_Shutdown

The console functions don't do much! That's right—you're the one that's going to fill them in with code each time. However, I did put a little something in Game_Main() to test for the Esc key and send a WM_CLOSE message to kill the window. This way you don't always have to close the window with the mouse or Alt+F4 key combination. Also, I'm sure that you've noticed the parameter list of each function looks like the following:

Game_*(void *parms = NULL, int num_parms=0);

The num_parms is just a convenience for you if you want to send parameters to any of the functions along with the number of parameters sent. The type is void, so it's flexible. Again, this isn't in stone and you can surely change it, but it's something to start with.

Finally, you might think that I should have forced the window to be full screen without any controls by using the WS_POPUP style. I could have done this, but I'm thinking of making them windowed for a number of demos so that they're easier to debug. We can also change to full screen on a demo-by-demo basis, so let's leave it windowed for now.

C++

If you're a C programmer, the syntax Game_Main(void *parms = NULL, int num_parms=0) might look a little alien. The assignment on-the-fly is called default parameters. All it does is assign the parameters the listed default values so you don't have to type in parameters if you know that they are the same as the default values. For example, if you don't want to use the parameter list and don't care if *parms == NULL and num_parms == 0, you can call Game_Main() just like that—without parameters. On the other hand, if you want to send parameters, you would have to use Game_Main(&list, 12), or something similar. Take a look at Appendix D for a short tutorial on C++ if it still seems fuzzy.


If you run T3DCONSOLE.EXE on the CD, you won't see much other than a blank window. The cool thing is that all you have to do is fill in Game_Init(), Game_Main(), and Game_Shutdown() with your 3D game code and you have a million dollars! Of course, we have a little ways to go, but we're getting there <BG>.

As a final demo of using the T3D Game Console, I have created an application based on it called DEMO4_9.CPP. It's a 3D star field demo—not bad for GDI. Check it out and see if you can zmake it speed up and slow down. The program once again illustrates the erase, move, draw animation cycle. It also locks the frame rate to 30 fps with our timing code.

      Previous Section Next Section
    



    JavaScript EditorAjax Editor     JavaScript Editor