The Internet is Watching You.
C++/D3D Pong Tutorial 01: Setting up the Project
Alright, the time has come for me to start up my tutorials again. Suppose I’ll start off with creating a Pong clone using C++ and Direct3D 9 (the game will be in two dimensions, though, for this product. Perhaps a 3D Pong tutorial can come later.)
Welcome to the D3D Pong Tutorial Series
Throughout this tutorial series, we will be developing a two-dimensional Pong clone using C++ and Direct3D 9. The tutorial assumes basic knowledge of the C++ language, as well as basic familiarity with namespaces, pointers, and the Microsoft Visual Studio IDE.
System Requirements
This tutorial series assumes that the following are true:
1) You have the DirectX SDK installed and configured on your system.
2) You know how to configure your IDE to use the header files and libraries included within the DirectX SDK
3) You know how to set up a new Win32 project (vice the use of a console project) in your IDE
4) You know how to add static libraries to a project within your IDE
Tutorial Description
This tutorial covers the first part of the D3D Pong project. We will create a Windows Application project, add the appropriate libraries, and will create the game/application window. In the next tutorial, we will cover setting up Direct3D, and will lay out the framework for the game engine.
Starting Words
In this tutorial series, I’m not going to give instructions to any particular IDE. I personally use Visual Studio 2010 B2 right now, and will at least be assuming the use of Visual Studio as far as some code samples go. If your particular compiler toolchain doesn’t support the
#pragma once
directive, simply replace any instances of that with the following:
#ifndef _FILENAME_H_ #define _FILENAME_H_
and put a
#endif
at the end of your file. This should be habit for most C++ developers, but I’m including this notice for the people who aren’t as familiar as the rest of us.
Project Setup
Go ahead and create a new Win32 Project within your IDE. Make sure that you are creating an empty Windows Application project, without MFC or any other fancy ties.
At this point in the project, we’re only going to add a single library to the project: winmm.lib.
Code Listing 1: WinMain.h
#pragma once // Trim the size of Windows.h #define WIN32_LEAN_AND_MEAN // Global Header Files #include <Windows.h> // Function Declarations int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int); LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
This header should look standard to anybody with any Win32 API experience. Defining WIN32_LEAN_AND_MEAN strips a lot of the contents of Windows.h that we’ll never need, which will shorten the build time for the project. After bringing in the Windows header, we declare the two primary functions of any Windows application: WinMain and WinProc. Onto the big one..
Code Listing 2: WinMain.cpp
#include "WinMain.h" // Global Variables bool g_bGameOver;
We start by including the WinMain.h header file that we created from the first code block, then define a global boolean variable called g_bGameOver. This variable will actually later be declared in our engine’s main header as an external variable, so that the rest of the game code can access it, but we are going to have the declaration done within WinMain.cpp.
// Window Callback
LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
// Called when the game window is closed
case WM_QUIT:
case WM_CLOSE:
case WM_DESTROY:{
g_bGameOver = true;
} break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
This is our Window procedure, which handles all events on the game window. We are only worried about three events, which all relate to the same thing: the user exited the game. Through this method, we can perform any last-minute computations before we actually exit the application.
// Application Entry Point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
// Local Variables
MSG msg; // Message Structure
HWND hWnd; // Window Handle
WNDCLASSEX wc; // Window Class Structure
// Setup Globals
g_bGameOver = false;
Moving onto the Application’s entry point, we declare three variables in the local scope to hold our messages, our window handle, and the window structure itself, then assign a value of false to the g_bGameOver global.
// Fill the structure wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WinProc; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = L"GameWindow"; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // Register the structure RegisterClassEx(&wc);
Standard Win32 structure filling. The things of note here are the assigning of a window icon, a cursor, a Small Icon, and most importantly, the window’s class name. The class name is important because it is what we will use to tell CreateWindowEx what it will use as window class when creating the application window.
// Create the Program Window
hWnd = CreateWindowEx(NULL, // dwExStyle
L"GameWindow", // Class Name - must match the lpszClassname of a registered window class
L"D3D Pong Tutorial", // Window Title
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // dwStyle
0, 0, // Screen Coordinates (X, Y)
640, 480, // Screen Size (Width, Height)
NULL, // Parent Window
NULL, // Menu
hInstance, // Instance Handle
NULL); // Extra Parameters
// Ensure that there were no creation errors
if(!hWnd)
{
MessageBox(NULL, L"Error Creating Application Window", L"Fatal Error", MB_OK | MB_ICONERROR);
return 0;
}
Standard window creation code. Always make sure that you test pivotal objects and ensure that they were actually created before attempting to use them. If our window isn’t created, we can’t do anything at all. Note that, like in the class definition, we are putting an L in front of the strings – this casts native strings into the LPCWSTR type, which will ensure that it is formatted as intended for the window.
// Display the window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Message Loop
while(!g_bGameOver)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Exit
return 0;
}
Finally, we show the window, do an initial Update call, and begin listening for messages. While this tutorial wasn’t much, especially for anybody experienced with the Win32 API, it provides us a firm ground on which we can start the rest of the tutorials in the series.
Code Listing 3: WinMain.cpp (Full Listing)
Just for reference, here is the complete WinMain.cpp file:
#include "WinMain.h"
// Global Variables
bool g_bGameOver;
// Window Callback
LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
// Called when the game window is closed
case WM_QUIT:
case WM_CLOSE:
case WM_DESTROY:{
g_bGameOver = true;
} break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// Application Entry Point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
// Local Variables
MSG msg; // Message Structure
HWND hWnd; // Window Handle
WNDCLASSEX wc; // Window Class Structure
// Setup Globals
g_bGameOver = false;
// Fill the structure
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = L"GameWindow";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// Register the structure
RegisterClassEx(&wc);
// Create the Program Window
hWnd = CreateWindowEx(NULL, // dwExStyle
L"GameWindow", // Class Name - must match the lpszClassname of a registered window class
L"D3D Pong Tutorial", // Window Title
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // dwStyle
0, 0, // Screen Coordinates (X, Y)
640, 480, // Screen Size (Width, Height)
NULL, // Parent Window
NULL, // Menu
hInstance, // Instance Handle
NULL); // Extra Parameters
// Ensure that there were no creation errors
if(!hWnd)
{
MessageBox(NULL, L"Error Creating Application Window", L"Fatal Error", MB_OK | MB_ICONERROR);
return 0;
}
// Display the window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Message Loop
while(!g_bGameOver)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Exit
return 0;
}
The remaining tutorials in this series will be set up as a series of code blocks, vice this single, full-listing, except under certain circumstances. I included the full code listing for this because it doesn’t require a lot of explanation for people who are at least passingly familiar with the Win32 API.
Comments are closed.