Software Design Description for the Fireball program, version 1.2.0.0.
The Fireball program is a logic game, whose purpose is to logically deduce the location of hidden posts on a game grid, by firing cannonballs into the grid and observing where the cannonballs emerge. Fireball is a dialog-based MFC application, and runs on Windows 95 through XP.
The game grid is laid out as a logical grid in pixels, and placed inside the dialog box window.
Figure
1 – Game board
overview

The basic unit of size in the game board is the constant CELLSIZE (defined in constants.h). This sets the size of one cell in pixels. In this version, CELLSIZE is set to 20 pixels. This is fine for a 640 x 480 or higher resolution display.
The game grid and cannon rows are arrays. The game grid is a square, so only one dimension need be specified. The size of the game grid (in cells) is defined by the constant NUMCELLS, which is set to 10 for a 10 x 10 grid. Each cannon row and column has NUMCELLS cannons.
To simplify drawing of the cannons and game grid, each of these five objects is treated as a two-dimensional array. The top and bottom rows are [1 x NUMCELLS], the left and right columns are [NUMCELLS x 1], and the game grid is [NUMCELLS x NUMCELLS]. This allows the same drawing function to be used to paint all five game objects.
The board, the cannon rows and cannon columns were initially laid out on paper, and the pixel positions calculated and defined as constants in CONSTANTS.H. Since the board cannot change at runtime, this was the simplest method of designing the board layout. The detailed layout is:
Figure
2 – Detailed Game
Board Layout

Each of the (X, Y) coordinates is defined in CONSTANTS.H. In
addition, the entire board is offset in the dialog box window, so that it
appears centered. The offset is defined as an
(OFFSETX, OFFSETY) offset in CONSTANTS.H and is added to the object’s position
when drawing, and subtracted from the mouse coordinate when the mouse is
clicked. That allows all game board operations to operate on the logical
coordinates, rather than the physical coordinates. The entire game board can
then be moved anywhere in the main window by simply changing the values of
OFFSETX and OFFSETY.
CBoard The game board object. This is a Singleton object. Contains the arrays of cannons and the game grid array. Each array has a structure to define the array’s location, dimensions, and list of BMP images that can be drawn in the cells. Uses an MFC CImageList object to hold the cell images, since they are actually bitmap arrays. The DrawArray() function draws a specific object, and the Draw() function calls DrawArray() for each of the five objects.
CCannonBall The cannon ball itself. This is a Singleton object that is used by CBoard. The object contains functions to move the ball and determine the exit location. The Draw() function draws the entry and exit cannonballs.
CMyBitMap Used to hold and draw the background bitmap. Taken from an MFC book and modified for this purpose. Not the most versatile bitmap class, but it works. The Draw() function draws the bitmap on screen.
CDice A dice object, used in CBoard::InitGame() to generate posts in random locations.
CAboutDialog The About box with the version information.
CFireballDlg The main dialog box object. Created by the App Wizard. The CBoard and CCannonball objects are created in the OnInitDialog() event. The OnPaint() event calls the CMyBitMap::Draw() function to draw the background, then calls the CBoard::Draw() function to draw the board objects, and then calls the CCannonBall::Draw() function to draw the entry and exit cannonballs.
CSound Plays WAV files or resources, given a logical sound name.
CUserInterface Wrapper around CFireballDlg, so that the other classes can access the UI without having to know the details.
CFireballApp The MFC application object. Created by the App Wizard.
The game objects are drawn on screen. Each of the five game objects also has an array of data structures to define the object’s appearance:
struct CellArrayType { // Defines
the type of array and images.
CRect rcLocation; //
Array screen location, normalized to OFFSET.
CImageList imgImages; //
Imagelist for cell BMPs.
int iNumCellsX; //
Number of cells in the X direction.
int iNumCellsY; //
Number of cells in the Y direction.
};
The CBoard object defines the game board, and contains five CellArrayType structures, one for each of the five objects:
CellArrayType cTopRow; // Defines Top row
of cannons
CellArrayType cBottomRow; // Defines Bottom row
of cannons
CellArrayType cLeftCol; // Defines Left
column of cannons
CellArrayType cRightCol; // Defines Right
column of cannons
CellArrayType cBoard; // Defines Game
grid
Drawing a CellArrayType game object is done is a loop as follows (in PDL):
FOR y = 0 to iNumCellsY - 1 DO
FOR x = 0 to iNumCellsX - 1 DO
Draw the image at cell (x, y)
END FOR
END FOR
Basically, the draw function is a raster scan from left to right, then down. The top and bottom rows are [1 x NUMCELLS], the left and right columns are [NUMCELLS x 1], and the game grid is [NUMCELLS x NUMCELLS]. This allows the two cannon rows, the two cannon columns and the game grid to be drawn using the same draw function.
The CellInfoType structure defines the contents of each individual cell in an object array. This allows each cell to have a different appearance:
struct CellInfoType { // Defines
the contents of each cell in an array.
CImageList* pImages; //
Pointer to the imagelist of display BMPs.
int iImageIdx; //
Index of image in list to display.
int iData; //
Data contents of the cell.
};
The draw function will draw pImages[iImageIdx] when drawing a cell. The image list contains the BMP, which is defined as a bitmap resources in the .RC file. Each BMP contains images for that cell. The appearance of a cell is changed by changing the index in the iImageIdx element of the CellInfoType array. Indexes are given logical definitions in CONSTANTS.H, allowing images to be indexed by name rather than number.
The CBoard object also contains five arrays of CellInfoType, such that there is one CellInfoType data structure for each individual cell in each of the five objects:
CellInfoType aTopRow[NUMCELLS];
CellInfoType aBottomRow[NUMCELLS];
CellInfoType aLeftCol[NUMCELLS];
CellInfoType aRightCol[NUMCELLS];
CellInfoType aBoard[NUMCELLS][NUMCELLS]; // Format is aBoard[y][x];
NOTE: Due to the method used to traverse the CellInfoType arrays when drawing, the format for accessing elements of the two dimensional aBoard array is aBoard[y][x].
The CellInfoType arrays and the CellArrayType structure are initialized by the CBoard object constructor. The arrays and structures work together to define and draw the game elements. Each CellInfoType array has a corresponding CellInfoType structure. This makes the final logic for drawing the rows, columns, and board:
CBoard::DrawArray(CellArrayType, CellInfoType)
function:
Start at the first element of the CellInfoType array
FOR y = 0 to CellArrayType.iNumCellsY - 1 DO
FOR x = 0 to
CellArrayType.iNumCellsX - 1 DO
Get BMP image from
CellInfoType.pImages[iImageIdx]
Draw the image at cell (x, y)
Increment the CellInfoType
pointer to the next element
END FOR
END FOR
When the mouse is clicked, the mouse coordinate is used to calculate which object, and which cell within the object, was clicked. This is more efficient than using a separate command target for each cell. CONSTANTS.H defines macros for calculating index positions in the object arrays, given the X or Y mouse coordinate.
CALCINDEX(axis) calculates the index “n” of the array, given the logical mouse coordinate of the applicable axis (i.e. relative to the logical origin of the board). For example, to determine the X index, call CALCINDEX with the X coordinate of the mouse. Note that if the mouse is not actually within an object, the returned index will either be less than zero or greater than NUMCELLS. A test must be performed to determine if the index is really a valid index.
ISVALIDINDEX(idx) returns TRUE if idx is between 0 and (NUMCELLS – 1), FALSE if not. If TRUE, then the <axis> mouse coordinate that was passed to CALCINDEX() can be used to index an object’s array. However, it still doesn’t identify which object the mouse is in. But it does mean that once the object has been determined, the index can be used to directly index the object’s CellInfoType array.
The CBoard::PointInObject(CPoint) function returns the object that the CPoint was in, or IN_NONE if it was not inside an object.
The general logic for handling the left mouse button is then (in PDL):
CFireballDlg::OnLButtonDown(mouse_location) function:
Normalize mouse_location by subtracting (OFFSETX, OFFSETY)
Calculate the x and y indices for the mouse_location
IF (mouse_location) is inside a CBoard object THEN
Do the mouse click operation for
<object> at cell index (x, y)
Redraw board as needed
END IF
The CBoard::DoMouseClick() function handles the actual work of doing the mouse click operation:
CBoard::DoMouseClick(object, x, y)
SWITCH (object)
CASE click
is any cannon row
Initialize the shot
Set initial direction, entry
and exit cells
REPEAT
Look ahead for posts
IF a post(s) is ahead
THEN
Change ball
direction
END IF
Move ball one cell
Mark cell as appropriate
(tutorial mode)
UNTIL Ball exits grid
CASE click
is in the game grid
Rotate cell image one click,
from <blank> to <X>, to <?>, and back to <blank>
Redraw the board
END SWITCH
The general logic for handling the right mouse button is (in PDL):
CFireballDlg::OnRButtonDown(mouse_location) function:
Normalize mouse_location by subtracting (OFFSETX, OFFSETY)
Calculate the x and y indices for the mouse_location
IF (mouse_location) is inside the game grid object THEN
IF there is a post there THEN
Mark the cell with a post
image
ELSE
Mark the cell as an incorrect
guess
Penalize as appropriate for a
missed guess
END IF
Redraw the board
IF all shots are expended THEN
IF all posts were correctly
placed THEN
You won!
ELSE
You lost!
END IF
END IF
END IF
Note that the game is not checked for a win/lose until a guess is made by right-clicking on a cell. This allows the last shot to be fired and still allow the person to make a guess.
Figure
3 – Class
Definitions

Figure
4 – Class
Relationships

Figure
5 – Sequence
Diagram
