Introduction to Windows Game Programming
Terms, Concepts, Functions

by PhilVaz


GAME LOOP

WIN32 PROGRAMMING

COORDINATE SYSTEMS (2D and 3D)

MATH CONCEPTS (Vectors, Formulas)

GRAPHICS CONCEPTS (GDI, DirectDraw, OpenGL)


GAME LOOP

A more advanced game architectural design might include the following: Windows Message handling, Game Input,  Logic, Networking, Output, Graphics, Sound, Physics, Resources and Databases, and more

advanced game architectural design

see GameLoop1.cpp for where GameInit, GameMain, GameQuit functions go in a Win32 game loop


WIN32 PROGRAMMING

WinMain( ) and WinProc( )int WINAPI WinMain( .... )

{   // fill in the window class structure here
    // save the game instance handle
    game_instance = hinstance;
    // register the window class
    RegisterClassEx( ..... );
    // create the window
    CreateWindowEx( ..... );
    // save the game window handle
    game_window = hwnd;

    GameInit( ); // game initialization function

    // enter main event loop using PeekMessage() to retrieve messages
    while(TRUE)
    {
        PeekMessage( ..... );  // check for Windows messages
        TranslateMessage ( ... );
        DispatchMessage( ... );

        GameMain( );  // game main processing function

    } // end while

    GameQuit( );  // game quit function and clean up before exit

    // return to Windows

} // end WinMain

see GameLoop1.cpp for a sample WinMain and WinProc

Windows monitors messages while applications runningLRESULT CALLBACK WinProc( ..... )
{   // main message handler of the system
    switch(msg)   // what is the message
    {
        case WM_CREATE:  // do initialization
        case WM_PAINT:  // validate window
        case WM_DESTROY:  // kills application
        case WM_MOUSEMOVE: // read mouse
        {
             // Loword is X pos
             Xmouse = LOWORD(lparam);
             // Hiword is Y pos
             Ymouse = HIWORD(lparam);
        }
    } // end switch
    // process any default messages
    return (DefWindowProc( ..... ));
} // end WinProc

see GameLoop1.cpp for a sample WinMain and WinProc


COORDINATE SYSTEMS

800 x 600 screen coordinates of Vazteroids (c) 2003 by PhilVaz2D GAMES

the X (left and right) and Y (up and down) coordinates local to your game objects or sprites (not required if bmp or other image sprites), for example: the rocks and ship in my Vazteroids.cpp used Local coordinates for vertices (4 points for the ship, 9 points for the rocks) and were drawn using the GDI function Polygon(  )

if we have a side-scrolling or vertical-scrolling game or otherwise large "world" that is larger than the screen we'll need X, Y World coordinates (or Tile coordinates) in addition to X, Y Screen coordinates, see my Megaman4.cpp for a side-scrolling demo that uses Tile coordinates

the X, Y coordinates corresponding to the size of your screen display resolution (normally 640 x 480 or 800 x 600) where your sprites are placed on screen

3D copter model showing local coordinates (triangle vertices)3D GAMES

the X (left and right), Y (up and down), Z (into or out of the screen) coordinates local to your game objects (or 3D models), for example: see my LoadASCModel.zip for a simple copter ASC model demo around 3000 polygons (or 3000 triangles and vertices)

the X, Y, Z coordinates for where the game object is placed or positioned in the "world" (normally the World coordinates for your 3D object or model would be the exact center of the model which makes it easier for collision detection), for example: the copter below (and its 3000 triangles) is placed in the 3D world using its single X, Y, Z World coordinates

3D copter model placed in world coordinates of VazTank (c) 2004 by PhilVazthe X, Y, Z coordinates for where your "camera" is or where the player is currently looking (in "first-person" shooters typically the camera and the player's look direction would be the same)

the X, Y coordinates corresponding to your screen display resolution (normally 640 x 480 or 800 x 600), taken care of by OpenGL at set up (glViewport) and automatically when drawing your 3D scene

 

 

 


MATH CONCEPTS

FORMULAS

To find the distance (also called magnitude or length) between two points or objects:

To aim a enemy bullet directly at an object, or move enemy in the direction of player:

// From Vazteroids.cpp

// aim UFO bullet directly at ship
dx = Ship.xcenter - UFO.xbullet; // difference in x
dy = Ship.ycenter - UFO.ybullet; // difference in y
m = (float)sqrt(dx*dx + dy*dy); // magnitude (distance)

UFO.xbmove = (dx/m) * BULLET_SPEED;
UFO.ybmove = (dy/m) * BULLET_SPEED;

// From VazTank.cpp

// enemy tank chasing player on ground (note: y-axis becomes z-axis instead)
dx = Player.x - x; dz = Player.z - z; // get diff between enemy and player
m = (GLfloat)sqrt(dx*dx + dz*dz); if (m == 0.0f) m = .0001f; // get magnitude (distance)

if (Enemy[i].type == ENEMY_TANK) // only enemy tanks will change direction
{
    Enemy[i].dx = (GLfloat)((rand( )%40) - 20.0f) * .01f; // move random on x
    Enemy[i].dz = (GLfloat)((rand( )%40) - 20.0f) * .01f; // move random on z
    if (game_state == GAME_STATE_GAME_RUN) // move toward player also
        { Enemy[i].dx += (dx/m) * .3f; Enemy[i].dz += (dz/m) * .3f; }
} // end if enemy tank

// From VazTank.cpp

EBullets[i].x = x; EBullets[i].y = y; EBullets[i].z = z;

// aim bullet directly at player, if copter bullet then need y vector too
dx = Player.x - x; dz = Player.z - z; dy = 0; if (y > 0) dy = Player.y - y;
m = (GLfloat)sqrt(dx*dx + dy*dy + dz*dz); if (m == 0.0f) m = .0001f;

// adjust aim to miss slightly based on difficulty level
ax = (GLfloat)((rand( )%40) - 20.0f) * .005f; az = (GLfloat)((rand( )%40) - 20.0f) * .005f;
if (game_difficulty == DIFFICULTY_EASY) { ax *= 2.0f; az *= 2.0f; }
if (game_difficulty == DIFFICULTY_NORMAL) { ax *= 1.5f; az *= 1.5f; }

EBullets[i].dx = (dx/m) * BULLET_SPEED + ax; // save bullet dx plus miss
EBullets[i].dz = (dz/m) * BULLET_SPEED + az; // save bullet dz plus miss
EBullets[i].dy = (dy/m) * BULLET_SPEED; // straight ahead if tank, downward if copter

EBullets[i].count = BULLET_DURATION - 25; // shorter range than player

// From Vazteroids.cpp
// note: here I already pre-computed the cos and sin values in an array

Ship.xmove += xdir[Ship.angle] * THRUST_SPEED;
Ship.ymove += ydir[Ship.angle] * THRUST_SPEED;

// From VazTank.cpp

GLdouble xd,zd; // x and z delta
// note: y-axis becomes the z-axis since tank is on the ground

xd = steps * cos(Player.Angle); // moves on X plane in player direction
zd = -steps * sin(Player.Angle); // moves on Z plane in player direction

Player.x += (GLfloat)xd; // do the move on X
Player.z += (GLfloat)zd; // do the move on Z

// From Vazteroids.cpp
// note: cos and sin were pre-computed in an array

Bullets[i].xmove = xdir[Ship.angle] * BULLET_SPEED;
Bullets[i].ymove = ydir[Ship.angle] * BULLET_SPEED;
Bullets[i].duration = DURATION_FOR_SHIP_BULLET;

// From VazTank.cpp

Bullets[i].dx = BULLET_SPEED * (GLfloat)cos(Player.Angle); // x direction
Bullets[i].dy = Player.Look / 16.5f; // y direction
Bullets[i].dz = -BULLET_SPEED * (GLfloat)sin(Player.Angle); // z direction

To rotate a point around the origin (0,0) requires the following Trig formula:

xnew = x * cos(angle) - y * sin(angle)
ynew = y * cos(angle) + x * sin(angle)

see also my Rotate Points in 2D space which allows you to rotate a point and specify the number of angle positions -- this is how I pre-computed the rotation positions for the 4 points of my ship in Vazteroids.cpp

In OpenGL using 3D this math is taken care of using the glRotatef(  ) function.
example: glRotatef(Enemy[i].Angle, 0.0f, 1.0f, 0.0f);  // rotate by angle degrees on y axis


GRAPHICS CONCEPTS

// go full screen
ChangeDisplaySettings(&game_screen, CDS_FULLSCREEN);

// get the GDI device context
game_dc = GetDC(game_window); 

// select an object (such as white brush)
SelectObject(back_dc, white_brush);

// plot a single pixel with color c
SetPixel(back_dc, xi, yi, c);

// fill rectangle (erase the back buffer)
FillRect(back_dc, &back_rect, black_brush);

// draw an ellipse (circular) to back buffer
Ellipse(back_dc, x1, y1, x2, y2);

// draw a polygon (9 points) to back buffer
Polygon(back_dc, points, 9);

// blit (bit block transfer) or copy back buffer to front buffer
BitBlt(game_dc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, back_dc, 0, 0, SRCCOPY);

// blit a single sprite or block of pixels (no transparency)
BitBlt(back_dc, x, y, BLOCK_SIZE, BLOCK_SIZE, bmp_dc, 0, 0, SRCCOPY);

// blit a single sprite with transparent background color (bug in Win98, only Win ME/XP work)
TransparentBlt(back_dc, Vaz.x, Vaz.y, BLOCK_SIZE, BLOCK_SIZE, bmp_dc, 0, 0, BLOCK_SIZE, BLOCK_SIZE, RGB(0,0,0));

LPDIRECTDRAW game_draw_main = NULL; // dd main object
LPDIRECTDRAWSURFACE game_draw_surface = NULL; // dd primary surface
LPDIRECTDRAWSURFACE game_draw_back = NULL; // dd back surface
DDSURFACEDESC game_draw_desc; // dd surface description
DDSCAPS game_draw_caps; // dd surface capabilities
LPDIRECTDRAWCLIPPER game_draw_clip; // dd surface clipper

// create base IDirectDraw interface
DirectDrawCreate(NULL, &game_draw_main, NULL);

// set cooperation to full screen
IDirectDraw_SetCooperativeLevel(game_draw_main, game_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);

// set display mode to specific resolution
IDirectDraw_SetDisplayMode(game_draw_main, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP);

// create the primary surface with a back buffer
IDirectDraw_CreateSurface(game_draw_main, &game_draw_desc, &game_draw_surface, NULL);

// get the pointer to the back buffer
IDirectDrawSurface_GetAttachedSurface(game_draw_surface, &game_draw_caps, &game_draw_back);

// set the clipper on left and right sides of screen
IDirectDraw_CreateClipper(game_draw_main, 0, &game_draw_clip, NULL);
IDirectDrawClipper_SetHWnd(game_draw_clip, 0, game_window);
IDirectDrawSurface_SetClipper(game_draw_back, game_draw_clip);

// clear the back buffer to black
IDirectDrawSurface_Blt(game_draw_back,NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT, &back_fill);

// blit (bit block transfer) a tile or sprite to back buffer (no transparency)
IDirectDrawSurface_Blt(game_draw_back,&temp_rect,hsky,&tile_rect,DDBLT_WAIT,NULL);

// blit a tile or sprite with transparency
IDirectDrawSurface_Blt(game_draw_back,&temp_rect,hbmp[meg_pos + meg_dir],&bmp_rect,DDBLT_WAIT | DDBLT_KEYSRC, NULL);

// copy/swap/flip back buffer to front buffer
IDirectDrawSurface_Flip(game_draw_surface,NULL,DDFLIP_WAIT);

ChoosePixelFormat(game_dc, &pfd);   // match the pixel format
SetPixelFormat(game_dc, pf, &pfd);   // set the pixel format
wglCreateContext(game_dc);    // create the rendering context
wglMakeCurrent(game_dc, game_rc);    // make it current

// set up screen width and height
glViewport(0, 0, width, height);

// set up 3D camera perspective for 3D games
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 5000.0f);

// set up 2D display for 2D games (or 2D HUD or text)
glOrtho(0, width, height, 0, -1, 1);

glBegin(GL_TRIANGLES);
     // specify vertices and draw triangles to back buffer here
glEnd();

glBegin(GL_QUADS);
     // specify vertices and draw quads (rectangles) to back buffer here
glEnd();

// swap (flip) back buffer to front buffer
SwapBuffers(game_dc);


back to www.VazGames.com