Alex Russell's Game Programming Tutorial using DX
Introduction . Chapter 1 . Chapter 2 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6 . Chapter 7
Chapter 7
Using a Windows Application with DX
Console mode programs were never meant to run graphics full screen. We will now create a basic windows program skeleton suitable for use with DX games.
At this point Build the project. It should compile and link. If run all it will do is show a black screen until you press ALT-F4. This is a good starting point for any simple DX project.
A Simple Game - Breakout
Now on to a small game - breakout. Before coding anything you must do at least some design work. For larger games more design work is required to have any chance of success. You should have the following things documented at a minimum before starting any coding:
A commercial game may have a books worth of documents done before any coding is done. For a simple game like this we only need a simple design doc.
Design Doc for Breakout
This is a very simple breakout game. There are two sections of bricks near the top of the screen. A single paddle controled by the mouse at the bottom of the screen, one ball, and a score indicator. The ball starts on the paddle, moving up when a mouse-button is pressed. A ball is 'lost' each time it is alowed to move off the bottom of the screen. Each brick in the lower section is worth 1 point, each brick in the upper sections is worth 5 points.
Art: brick, ball, paddle
Music: looping midi song
Sound: a bounce sound each time the ball hits something.
Game flow
Start with intro screen. Text only, display for 5 seconds or a mouse button is pressed.
Game play then starts. The ball starts on the paddle, 'glued' in place until a mouse button is pressed. The ball then bouces on screen, making bricks dissapear as they are struck. Each brick struck gains points. The game ends if 5 balls are lost, or all bricks are hit. The player is given an option to play again. Repeat.
Code Details
Art will be done on one bmp file. The spriteEdit util will be used to make a single frame sprite from the bmp for the ball, brick, and paddle. A finite state machine will be used. There will be strict seperation of drawing and logic code.
Download the game source to see the details!
Introduction . Chapter 1 . Chapter 2 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6 . Chapter 7
Copyright 2004 (c), Alex Russell, All rights reserved
/*
breakout.cpp
march 8, 2004 jar - initial file
*/
#include "stdafx.h"
HWND g_hMainWnd;
HINSTANCE g_hInst;
// Foward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
CgsdxIO *gb_pDX=NULL;
typedef struct
{
int paused;
int done;
}
GameInfo_t;
GameInfo_t gb_Info;
HWND InitWindow(int iCmdShow)
{
HWND hWnd;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = LoadIcon(g_hInst, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH )GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = TEXT("");
wc.lpszClassName = TEXT("Basic DDX");
RegisterClass(&wc);
hWnd = CreateWindowEx(
WS_EX_TOPMOST,
TEXT("Basic DDX"),
TEXT("Basic DDX"),
WS_POPUP,
0,
0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
NULL,
NULL,
g_hInst,
NULL);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
SetFocus(hWnd);
return hWnd;
}
int DoLogic(CgsdxIO *dx)
{
if ( gb_Info.paused )
return gb_Info.done;
if ( dx->IsKeyDown(DIK_ESCAPE) )
gb_Info.done=1;
return gb_Info.done;
}
int DoDraw(CgsdxIO *dx)
{
int err=0;
if ( gb_Info.paused )
return 0;
dx->RectFill(NULL, 0); // fill screen black
dx->Flip();
return err;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
g_hInst = hInstance;
g_hMainWnd = InitWindow(nCmdShow);
if(!g_hMainWnd)
return -1;
// dx
CgsdxIO dx;
if ( dx.InitResource(0) )
return 0;
if ( dx.InitGraphics(1024, 768, 32, GSDX_FULL_SCREEN, g_hInst, g_hMainWnd) )
return 0;
if ( dx.InitSound() )
return 0;
if ( dx.InitIO() )
return 0;
gb_pDX=&dx;
gb_Info.done=0;
gb_Info.paused=0;
TRACE("[main] peek message\n");
PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE);
// run till completed
while ( msg.message!=WM_QUIT )
{
// is there a message to process?
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE) )
{
// dispatch the message
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
if ( !DoLogic(&dx) )
DoDraw(&dx);
else
{
//PostQuitMessage(0);
break; // all done - esc pressed
}
}
}
ShowCursor(TRUE);
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
WORD fActive, fMinimized;
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_ACTIVATE:
fActive = LOWORD(wParam); // activation flag
fMinimized = (BOOL) HIWORD(wParam); // minimized flag
TRACE("[WndProc] active= %d\n", fActive);
if ( fActive )
{
// un-pause
gb_Info.paused=0;
if ( gb_pDX )
{
gb_pDX->AcquireAllDevices();
}
}
else
{
// pause the game
gb_Info.paused=1;
}
break;
} // switch
return DefWindowProc(hWnd, message, wParam, lParam);
}
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
//#include