Software Engineering
Home Planning Requirements Writing Hazard Analysis Requirement Analysis Config Control Software Design Software Testing Software Standards Basic Logic

Software Design Case Study - Fireball Logic Game

The Problem

The game board is 10 x 10. The cannonball deflects off the posts in this fashion:

The game logic is to look ahead and see if there is a post ahead to the left, ahead to the right, or straight ahead. If not, then the ball can advance one cell. If there is a post ahead to the left, then the ball deflects to the right. If there is a post ahead to the right, then the ball deflects to the left.
With no posts nearby, the ball fired form the left goes straight through to the right. The red cannonball marks the entry and exit cells.
Each post exerts a field around it, so the ball bounces when there is a post nearby. The ball to the left has entered at the top, and bounced to the left.
When the ball hits a post head on, the ball bounces straight back. In the picture to the left, the ball was fired down, hit the post, and bounced straight back up.
When a ball tries to go between two posts, the result is a direct bounce back as well. This is because one post tries to defect the ball left, the other to the right. The result is a straight back bounce.

The player has a fixed number of shots, but repeating a previous shot does not count. Also, the player has to be able to click on a cannon to fire it, and to click on a game cell to guess if there is a post there.

The Design

First, Functional Decomposition was applied to decompose the game board into its components.

Each row of cannons has 10 cannons. The relationships are fixed by the size of the game grid.

The dimensions were then laid out in greater detail, also allowing space between the board and the cannons to show the cannonball's entry and exit. The size of each cell was fixed at 20 x 20 pixels, 20 x 40 pixels for cannons.

This gives five arrays of objects:

  • Board (10 x 10)
  • Left and Right cannon rows (1 x 10)
  • Top and bottom cannon rows (10 x 1)

Treating them all as two dimensional arrays allowed me to use the same drawing function for all five objects. Since the board is always square, I only have to define one dimension.

Rather than create a separate control for each cannon and game cell, I chose to draw them on screen and use the above map to calculate where a mouse occurred. Everything was normalized to the logical origin of (0,0).

Each of the (X, Y) coordinates in the game map are 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.

There is only one board and only one cannonball, so those were both made as Singletons.

Decoupling the User Interface

The board and cannonball often had to send information to, or get information from, the user interface. Because I do not like to tightly couple objects with their on-screen representation any more than is necessary, I created the CUserInterface object as a Bridge between the UI and the rest of the program. This object provides the interface to the UI, allowing the game objects to communicate with the UI in a safe manner. The object is a Singleton, so that only one will exist.

The Implementation

Click here for the complete Software Design Description.

Click here for the source code in C++. The classes CMyBitmap, CAboutDialog, and CDice are reusable as-is. The class CSound is reusable with modification to the sound definition array.

Unit Testing

To facilitate unit testing, I created a Tutorial mode that shows the path of the cannonball as it travels. Initially, the position of the posts were hard-coded by using a stub function for the random number generator. It simply returned a hard-coded sequence of positions. That allowed me to debug the ball navigation code, especially for multiple bounces..