Amazon Honor System Click Here to Pay Learn More

by Forest J. Handford

This chapter is is a very intense continuation of our Direct Draw coverage.  I will go fast so take it at your pace.

One of the most important aspects of game programming is the sprite.  No, a sprite isn't a mythical creature, it's a set of pictures that make up the animation of an object in your game.  Consider my second favorite game, Warcraft II.  In the game there is a a two headed ogre.  The ogre can look in 8 different directions.  The ogre has an axe that it uses to attack in 8 different directions.  When the ogre dies it has 4 different looks, each one being more decayed.  The 6 states and 8 directions of the ogre allow the ogre the ability to look 1 out of 20 ways at any point in the game.  Let's look at another example.  Pac-Man looks in four directions.  He can either have his mouth open or closed.  That allows 8 different looks for Pac-Man, not including his death sequence.  The developers of Pac-Man made a picture of all of Pac-Man's possible looks that probably looked similar to:

The first two lines show all the possible positions for Pac-Man when he is alive.  If you remember the game, every other step he took he would have his mouth open.  If Pac-Man was going right, we would draw the top left Pac-Man and then the middle left Pac-Man and then the top left Pac-Man again.  If he turned and started going up we would use the  top right Pac-Man followed by the middle right Pac-Man and back to the top right Pac-Man.  If Pac-Man died we would display the bottom row from left to right.  All of these pictures are in the same bitmap so that they are all loaded into memory at the same time.  A doubly linked list, which is basically a queue that has links in both directions, would hold the coordinates for the top and middle row.  Each node would have the coordinates for the open and closed mouth like this:

struct SpriteNode
   ClosedTopX;    // The top left X coordinate of Pac-Man with his mouth closed
   ClosedTopY;    // The top left Y coordinate of Pac-Man with his mouth closed
   ClosedBottomX;    // The bottom right X coordinate of Pac-Man with his mouth closed
   ClosedBottomY;    // The bottom left Y coordinate of Pac-Man with his mouth closed
   OpenTopX;    // The top left X coordinate of Pac-Man with his mouth open
   OpenTopY;    // The top left Y coordinate of Pac-Man with his mouth open
   OpenBottomX;    // The bottom right X coordinate of Pac-Man with his mouth open
   OpenBottomY;    // The bottom left Y coordinate of Pac-Man with his mouth open

We would also have a class to hold the death sequence.

Current video cards are being made with overlay capabilities.  Overlays are used to keep the primary surface the same while drawing over it.  The video cards that do allow overlays currently only support one overlay for the entire system.  If your application is in a window and another window is using an overlay you will not be allowed to use an overlay.  The solution to this is to ask for exclusive mode.  Exclusive mode lets you ask for and keep exclusive rights to a piece of hardware.  This isn't a friendly technique though.  A better idea is to be in full screen mode.  The user may not want your application to be in full screen mode so you should allow the user to decide, unless your application simply can't afford to be windowed.  A game like StarCraft or Quake would not run well in a window because the other applications would be sharing the resources and the palette.  Some video cards that allow overlays have alignment and scaling restrictions.  In our example program we will not use an overlay, if there are any alignment or scaling restrictions.  Here are the functions for overlays:

//This will show, hide, or move your overlay
UpdateOverlay(LPRECT lpSrcRect,       //Pointer to the source that can be NULL to use the
                                      //entire surface or to hide the overlay
    LPDIRECTDRAWSURFACES lpDDDestSurface,    //Pointer to the destination
    LPRECT lpDestRect,    //Pointer to the destination rectangle, NULL if you are hiding
                           //the overlay
    DWORD dwFlags,    //Control flags
    LPDDOVERLAYFX lpDDOverlayFx);    //Address for overlay effects

//Change the position according to where your window was moved
SetOverlayPosition(LONG lX, //The new X coordinate
    LONG lY);    //The new Y coordinate

The control flag should be set to DDOVER_SHOW if you want the overlay to be visible.  To hide the overlay use DDOVER_HIDE .  To use the source key, use the DDOVER_KEYSRC flag.  To use the destination key, use the DDOVER_KEYDEST flag.  Finally to use a DDOVERLAYFX structure for special effects use DDOVER_DDFX .

Palettes are color schemes.  If your in a window you must share the palette with all the other programs.  Most programs will use only a few colors so this may not always be a problem.  All surfaces can have palettes.  If you don't create a palette your hardware will pick one for you.  A palette can have 2, 4, 16 or 256 colors.  Here is what a palette entry looks like:
   BYTE peRed;    //amount of red color
   BYTE peGreen;    //amount of green color
   BYTE peBlue;    //amount of blue color
   BYTE peFlags;    //Control flags

This should bring back memories of high school art classes.  Every color is made up of red, green and blue.  The amount of each color component can be a value from 0 to 255.  0 would be none and 255 would be the most.  Black would be defined as follows:
Black.peRed = 255;

White would be the exact opposite with all 0 values.  For Red peRed would equal 255 an the other two colors would = 0.

Here are some useful palette functions defined in ddraw.h :
//Create a palette
CreatePallette(DWORD dwFlags,    //the capability flags
    LPPALETTEENTRY lpColorTable,    //An array of color values
    LPDIRECTDRAWPALETTE FAR * lplpDDPalette,    //A pointer to the new palette object
    IUnknown FAR * pUnkOuter);    //not yet used in DirectX so pass NULL here

//Associate a palette with one of your surfaces
SetPallette(LPDIRECTDRAWPALETTE lpDDPalette);    //Address of the palette you want to attach

//Returns the palette attached to a surface
GetPallette(LPDIRECTDRAWPALETTE FAR * lplpDDpalette);    //Pointer to the palette object

//The capabilities of the palette on the user's PC
GetCaps(LPDWORD lpdwCaps);    //address of capabilty flags

//Returns entries from the color table to an array
GetEntries(DWORD dwFlags,    //Currently unused by DirectX so you must use 0
    DWORD dwStartingEntry,    //Subscript of the first palette entry to return
    DWORD dwNumEntries,    //Number of palette entries to retrieve
    LPPALETTEENTRY lpEntries);    //Address of an array to be filled with the entries

//Change an entry in a color table to that of an array you have created
SetEntries(DWORD dwFlags,    //Currently unused by DirectX so you must use 0
    DWORD dwStartingEntry,    //Index of the first palette entry to change
    DWORD dwNumEntries,    //Number of palette entries to change
    LPPALETTEENTRY lpEntries);    //Address of an array that has the new values

Each pixel is created from the palette entries.  In windows palettes can become sloppy.  The 0 palette and 255 palette are used by the operating system and should never be changed.  If you do change them the colors of your borders and other application colors could be distorted.  Your application could use several palette entries.  If you are in a windowed application and other applications are using palette entries you have to compete with them.  The foremost application gets it's choice of palette entries.  Have you ever seen colors on your screen change when you switch applications?  That is caused by the applications running into each others palettes.  Whenever your application is restored you must restore your palette.

With palettes you can create palette animation.  If you want to change the screen colors without changing the pixels one by one you can change the palette your surface is attached to.  Palette animation can be useful if you just want to change one color.  Say your displaying your credit screen.  If you want the names to slowly fade you could change the palette entry so that it slowly is changed to that of the background color.  This can cause tearing so be watchful if what happens.

In our game we need to detect when our ship is hit.  To do this we will divide the playing field into squares.  The sprites will have it's position written in it's node.  Every time the shots or ship moves we will check to see if their X and Y values are equal.

Our PC can be going at varying speeds so we must use time values to decide when and where to draw our ship and shots.  The formula for where to draw it should look something like the following:
Direction + time since last update * speed

Clipping is the way to remove unwanted sections from the surface.  In windows when the windows are overlapping each other we have to clip anything that is usually drawn where a foreground application has been placed.  DirectX makes this very simple because you can associate a clipper to a surface.  The clipper will do all the work for us, hurray.  You will want to use the following functions to make use of the clipper:
//Create the clipper object
CreateClipper(DWORD dwFlags,    //Currently unused by DirectX so use 0
    LPDIRECTDRAWCLIPPER FAR * lplpDDClipper,    //pointer that will point to the new clipper
    IUnknown FAR * pUnkOuter);    //Currently unused by DirectX so use NULL

//Attach a clipper to a window
SetHWnd(DWORD dwFlags,    //Currently unused by DirectX so use 0
    HWND hWnd);    //The window where the clipping information is

//Attach a clipper to a surface
SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);    //The clipper for overlays and blitting

That's all you need to know for this chapter's example but first I would like to go back to resources stored in .rc files.  Here is what is actually in a resource file:
//Microsoft Developer Studio generated resource script.
#include "resource.h"

// Generated from the TEXTINCLUDE 2 resource.
#include "afxres.h"


// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
#pragma code_page(1252)
#endif //_WIN32

// Bitmap

SHIPS                   BITMAP  DISCARDABLE     "ships.bmp"
SHOTS                   BITMAP  DISCARDABLE     "shots.bmp"
GHOST                   BITMAP  DISCARDABLE     "ghost.bmp"



    "#include ""afxres.h""\r\n"



// Icon

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1               ICON    DISCARDABLE     "Space Adventure1.ico"
#endif    // English (U.S.) resources

// Generated from the TEXTINCLUDE 3 resource.

#endif    // not APSTUDIO_INVOKED

The compiler creates this to store information about your resources.  It is written in a C script and can be used by a non Microsoft compiler.  Avoid editing it because any edits can prevent the compiler from reading and editing it correctly.

Now here is our hottest game: SPACE ADVENTURE

< Space Adventure files >

In the next chapter I'm planning on getting into sounds but who knows, maybe I won't!


Amazon Honor System Click Here to Pay Learn More