CS4500 Software Design Specification, Version 2 (Detailed)
February 15, 2008
Team Here For Beer
1. Introduction
1.1 Purpose of this Document
This is the Software Design Specification for Team Here For Beer's Tower Defense game. This document will outline the software design and specification of our Tower Defense Game in addition to system architecture, system components, and software requirements as agreed upon by the customer and the project team.
The HFB Tower Defense Game is a DirectX based real-time strategy game targeted to the Windows platform.
1.2 Scope of the development project
A real-time strategy game titled: Here For Beer Tower Defense will be developed. The game will be made using C++ and the Microsoft DirectX 9.0 SDK. The game will be similar in genre to current hit Flash-based games (see: 1.4 References Section) but will harness the power of modern graphics hardware. The single player game will consist of a single grid space where a number of "maps" (number TBD) can appear. Each map will define a path in which the waves of enemies during that game will progress. The player can stop the enemies by building and upgrading towers on the grid, which will automatically attack enemies that are in their fire distance radius (in the tradition of typical tower based real-time strategy games).
The game will provide lasting single player value through its dynamic action and large spectrum of strategy, rather than through large amounts of graphical assets.
The project will also include a web front end programmed in Adobe Flash 9.0. The single player game can upload high scores via the internet to our server, which can later be browsed via the Flash-based front end.
1.3 Definitions, Acronyms, and Abbreviations
- DX9 - DirectX 9
- HFBTD - Here For Beer Tower Defense
- RTS - Real-Time Strategy
- SRS - Software Requirements Specification
- Twitch Game - A type of game where users must react quickly to circumstances in order to continue playing (such as Tetris)
- UI - User Interface
- Wave - A Group of enemies, or other entities that will arrive, and attempt to depart together.
1.4 References
Flash Tower Defense Game, Vector Based
Another Tower Defense Game
1.5 Overview of Document
This document will contain specifics about the design of our software. It is a high level explanation of how the game will function, and which components will be developed to help it do so. This document will also serve to explain the technologies used to develop the application, as well as the user's interaction with the application.
2. System Architecture Description
2.1 Overview of Modules / Components
- Game Application - HFBTD will consist of two main components running on independent threads (to seperate CPU and graphics lag from each other).
- Game Logic Component - This will be the main part of the project. This component will manage all the interactions during the actual gameplay between the different entities in the game. The game logic component will keep track of the following key items:
- User keyboard / mouse interaction.
- Enemy artificial intelligence.
- Player tower artificial intelligence.
- Game Rendering Component - This component of the application will run on its own thread and interact with DirectX on behalf of the application. This application will use the DirectX SDK 9.0.
- Game Logic Component - This will be the main part of the project. This component will manage all the interactions during the actual gameplay between the different entities in the game. The game logic component will keep track of the following key items:
- High Scores Server - There will be a small server application built to store and retrieve high scores set in the game.
- Web Front End - An Adobe Flash frontend application that will display the high scores achieved in the game thus far.
2.2 Structure and Relationships
2.3 User Interface Issues
The following image represents the main screen in the HFBTD application. The entirety of the game will take place in a screen that will look somewhat like the following:
The web interface will have a simple list based GUI for looking through the high scores that have been submitted to the database.
3. Detailed Description of Components
3.1 Component Template Description
| Identification | The unique name for the component and the location of the component in the system. |
| Type | A module, a subprogram, a data file, a control procedure, a class, etc. |
| Purpose | Function and performance requirements implemented by the design component, including derived requirements. Derived requirements are not explicitly stated in the SRS, but are implied or adjunct to formally stated SDS requirements. |
| Function | What the component does, the transformation process, the specific inputs that are processed, the algorithms that are used, the outputs that are produced, where the data items are stored, and which data items are modified. |
| Subordinates | The internal structure of the component, the constituents of the component, and the functional requirements satisfied by each part. |
| Dependencies | How the component's function and performance relate to other components. How this component is used by other components. The other components that use this component. Interaction details such as timing, interaction conditions (such as order of execution and data sharing), and responsibility for creation, duplication, use, storage, and elimination of components. |
| Interfaces | Detailed descriptions of all external and internal interfaces as well as of any mechanisms for communicating through messages, parameters, or common data areas. All error messages and error codes should be identified. All screen formats, interactive messages, and other user interface components (originally defined in the SRS) should be given here. |
| Resources | A complete description of all resources (hardware or software) external to the component but required to carry out its functions. Some examples are CPU execution time, memory (primary, secondary, or archival), buffers, I/O channels, plotters, printers, math libraries, hardware registers, interrupt structures, and system services. |
| Processing | The full description of the functions presented in the Function subsection. Pseudocode can be used to document algorithms, equations, and logic. |
| Data | For the data internal to the component, describes the representation method, initial values, use, semantics, and format. This information will probably be recorded in the data dictionary. |
3.2 Game Manager Component
| Identification | Game Manager |
| Type | Class |
| Purpose | The game manager is a class which controls most of the game logic. |
| Function | The game manager keeps track of the general state of the game (such as whether the player is currently playing or at the main menu, etc.) The component also keeps track of all drawable entities and gives those entities to the game renderer for drawing. It also updates the state of all game entities, such as towers and enemies. |
| Subordinates | The game manager is implemented using standard C++ OOP principles. |
| Dependencies | The game manager requires game entities to be created. It also requires a timer in order to update game state at predetermined intervals. The game manager will share entity information with the game renderer so that the game renderer can draw the primitives associated with game entities. |
| Interfaces | The game manager must communicate time-interval differences to all game entities so they can update their state. This will be communicated using methods exposed by game entities. It must also interface with the game renderer class. This will be accomplished by exposing a method that returns a pointer to the data structure containing entities. |
| Resources | The game manager requires enough memory to store the game entities. Because it also accesses methods exposed by game entities for each timer interval, it is fairly CPU intensive. |
| Processing | The game manager is initialized and initial game entities are created (such as maps and UI entities). User input is received to then enter the playing state. At this point, user input is received to allow the player to place tower entities on the map and to also send out enemies. These entities are also created and managed by the game manager. Each entity is accessed at predetermined timer intervals to tell them what to do. |
| Data | Game entities are stored as arrays of pointers. |
3.3 Game Renderer Component
| Identification | Game Renderer |
| Type | Class |
| Purpose | The game renderer displays the game using Direct3D. |
| Function | The game renderer initializes the Direct3D API and prepares the screen for drawing. Once initialized the game renderer loops continuously in its own thread as fast as possible. For each loop, it retrieves the list of game entities from the game manager and tells them to draw themselves to the screen. |
| Subordinates | The game renderer is implemented using standard C++ OOP principles. It is a simple class with a main function running in a continuous loop. |
| Dependencies | This component is highly dependent on the game manager component in order to retrieve entities to draw to the screen. It also depends on the DirectX 9 API for drawing entities to the screen. The game renderer component is very self contained, though it does allow other components to access the Direct3D handles so they may allocate graphics memory and draw things during the render cycle. |
| Interfaces | Communication to the graphics hardware is done via DirectX calls. All calls will be checked for errors and handled accordingly. The game renderer retrieves a vector array of game entities from the game manager. It calls the draw() method on each game entity. |
| Resources | This is the most resource intensive portion of the game. It loops as fast as possible and so uses a lot of CPU time. It does not monopolize the CPU because the DirectX graphics display portion causes the CPU to block while the graphics hardware renders pixels. This component requires a DirectX 9 capable graphics card. |
| Processing | First, the DirectX hardware and software is initialized. After that, a main loop is entered which retrieves the vector of game entities from the game manager. Each entity is then drawn to the screen by calling that entity's draw() method. The loop is then repeated. |
| Data | The game renderer only stores handles to the DirectX interface as public variables. |
3.4 Primitives
| Identification | Primitive |
| Type | Classes |
| Purpose | The primitive objects expose a simple way to create graphical objects that are eventually rendered to the screen. |
| Function | Each primitive has a location and type. It has access to the DirectX API and will draw itself when told to do so. |
| Subordinates | Each primitive is an abstract class which must be extended by a specific primitive type (such as line, point, etc.). |
| Dependencies | This component does not directly depend on any other objects, but almost all objects depend on it (notably, each game entity is built using primitive objects). |
| Interfaces | When a primitive is constructed, it must be given location, color, line width, etc. These values may be changed at any time. Each primitive type communicates to Direct3D to allocate graphics memory. Each primitive also exposes a draw() method which may be called. This method communicates with Direct3D to draw the primitive. |
| Resources | Each primitive type (not every primitive object) allocates a small amount of memory on the graphics card. This memory is then manipulated by each primitive object during its draw() cycle. |
| Processing | Each primitive type is initialized by the game renderer. This initialization phase allocates graphics memory. Each primitive object will then be created with parameters for X/Y coordinates, color, line width, etc. When the primitive is drawn, it uses these parameters to call DirectX methods to manipulate graphics memory and draw the primitive. |
| Data | Primitive attributes are stored as private variables. |
3.5 Game Entities
| Identification | Game Entity |
| Type | Classes |
| Purpose | The game entity class provides a way to organize multiple primitives into a single drawable object. |
| Function | The game entity is extended by other entity classes. These classes create groups of primitives and modify them during state updates. Game entities also encapsulate functionality of the given entity (such as targeting an enemy for a tower entity, etc.) |
| Subordinates | Each game entity is an abstract class that must be extended by other entity classes (such as a Tower or BasicEnemy). |
| Dependencies | All game entities extend this class. Each game entity depends on primitive objects for drawing themselves. The game manager calls methods in entities to have them perform certain activities. The game renderer depends on entities in order to draw them. |
| Interfaces | The game manager thread keeps track of all game entities. Each game entity exposes a method for drawing itself, which is executed by the game renderer. Other game entities that extend this object will have their own specific control methods that get called by the game manager. |
| Resources | Each entity must be given information about the current time for each timer fire event. |
| Processing | Entities will all perform different functions. In general, each entity will initially create the primitives required for drawing. Then each timer event, will manipulate their primitives to do animation/movement. For each draw() cycle of the game renderer, the game entity will loop through all its primitives and tell them to draw themselves. |
| Data | Primitives are stored in a simple vector array. Other state information is maintained as private variables. |
3.6 High Scores Web Service
| Identification | High Score Web Service |
| Type | Module |
| Purpose | The high score web service receives high scores from the game and stores them in a database. It also sends high scores in XML to be displayed by a frontend. |
| Function | The web service waits for a high score submission from the game. Once a high score is submitted it is checked for validity and then sent to be stored in a MySQL database. Once the scores are stored, they can then be accessed by the high scores frontend. The web service is called by the frontend with parameters to return certain subsets of the high scores in XML. |
| Subordinates | Both the high score submission and XML application are simple procedural scripts. There is simple error checking in both scripts. Upon success, each script will either successfully submit a high score or return a list of high scores. |
| Dependencies | Both scripts require access to the MySQL database. The score submission script interfaces with the Score class implemented in the game. The XML web service returns requested scores to the high score frontend. |
| Interfaces | The score submission exposes a simple interface where it accepts name, score and MD5 hash in GET parameters. It then returns a single line success/failure message. The XML web service also exposes an interface controlled by GET parameters that allows the frontend to restrict the high scores to certain subsets. These parameters affect the database queries performed. |
| Resources | The scripts require internet access to be accessed. Neither script is resource intensive as far as CPU/memory/storage requirements. |
| Processing | The submission script takes the high score parameters, appends a secret key and then creates an MD5 hash of these values. If the hash matches the hash given by the user the score will be stored in MySQL. The XML script can be called with no parameters or parameters to restrict to a certain subset. Based on these parameters, a SQL query is generated and executed. The results of the query are then used to generate an XML object, which is then told to render as XML and is output to the browser (in this case, the high score frontend). |
| Data | All data is stored in a simple MySQL database. The XML script temporarily stores high scores in an XML object. |
3.7 High Scores Frontend
| Identification | High Scores Frontend |
| Type | Module |
| Purpose | The high scores frontend displays high scores in an organized and intuitive fashion using Adobe Flash for easy browsing by players. |
| Function | The high scores frontend initially sends a query to the XML high scores web service to retrieve a list of the top X high scores. These are then displayed to the user. The user can then select other options to do more targeted searches/queries of the XML web service, such as searching by name or listing the lowest scores or paginating through large amounts of results. |
| Subordinates | The frontend has internal data structures for storing the XML results. It also has internal structure for keeping track of display state (such as pagination, etc.) |
| Dependencies | The high scores frontend requires data from the XML web service. |
| Interfaces | The frontend makes simple GET requests to the XML web service and is given results in a pre-determined format. This format includes success/failure error codes and is further described in the high score web service documentation. |
| Resources | The frontend requires Adobe Flash to be installed on the computer of the person accessing the frontend. |
| Processing | Initially a call is made to the XML web service to retrieve a small list of high scores, which is then parsed as XML and displayed to the user. The user may then select options to make a new request and the process begins again with the user parameters being sent to the XML web service. |
| Data | The high scores are interpreted and then stored in an XML object. |
4. Reuse and Relationships to other products
Graphically, HFBTD is being designed to use a few well written graphic functions to create complex graphical effects. Inheritance will play a major role in product implementation. This will allow for ease of reuse by creating many functions that are used by all entities in the game. In addition, we will be using a small set of rendering functions together to create our graphical interface. These functions will be written as efficiently as possible and will keep us from reimplementing the same code when we could be focusing on improving the overall experience of the game. Because the goal is to learn how to use DirectX, we are not reusing any existing DirectX game or graphics engines. This is because it is far more educational for us to implement the types of things we need ourselves than it is to dig through documentation to figure out how to manipulate an available open source engine.
5. Design decisions and tradeoffs
Our threaded design will allow the game logic to be operating independent of the rendering engine. This will help the game to scale well, and play the same across multiple types of systems because timing is going to be handled in a thread separate from graphics rendering. This decision was an important one to guarantee that if a player plays this game on his grandmother's machine, followed by his own he/she will get a similar experience.
The threaded design was also created with user experience in mind. Because input is constantly happening, and the game is constantly being updated the experience for the user should feel much smoother than if input was being processed in between screen renderings.
While there are many existing frameworks and programming languages that would greatly speed up the development process, we ultimately decided that we wanted to create our game using C++ and DirectX. The elegance and efficiency of C++ helped influence the decision, but it also comes with fewer restrictions and a different type of learning curve. Creating a game engine allows much more developer creativity than figuring out how to to configure an existing one - this tradeoff alone makes C++ and DirectX our development platform of choice.
Graphically, we made the decision to use vector graphics instead of traditional 2D sprites. We are currently planning on leaving 3D graphics as a future enhancement if time allows. This creates an interesting tradeoff, but ultimately we decided to go with the more math dependent vector graphics and leave sprites behind for all parts of our game. The advantage is that we won't have to spend any time in graphics editors tweaking our small images. The disadvantage is that animating vectors requires a lot more math than masking off sprites. Because of our background in science and not art, the decision to use vector graphics makes the most sense.
6. Pseudocode For Components
The following is the current proposed object design.
- Primitive
- Description: The building block for all objects rendered to the screen. This is an abstract class.
- Public
- Primitive()
- Constructor: Initializes private data structures.
- virtual static bool Initialize()
- Initializes Direct3D memory for primitive (can't be done in constructor because of possibility of failure)
- virtual bool draw()
- Called by the rendering thread to draw the primitive to the DirectX backbuffer.
- Primitive()
- Line extends Primitive
- Triangle extends Primitive
- Circle extends Primitive
- Text extends Primitive
- Particle extends Primitive
- GameEntity
- Description: This is any group of primitives drawn to the screen. It could consist of the map grid, enemies, turrets, explosions, etc.
- Public
- GameEntity()
- Constructor: Initializes private data structures (such as array of primitives).
- void setLocation(float x, float y)
- Moves entity to given location.
- void setVelocity(float velocity, float x, float y)
- Sets the speed of the entity and the direction of movement.
- void setAcceleration(float xAccel, float yAccel)
- Sets acceleration for x/y directions.
- void draw()
- Called by game renderer thread, calls draw() method on all entities in entityPrimitives array. May need to implement mutexes to prevent GameManager from altering primitives while GameRenderer is reading them.
- GameEntity()
- Private
- vector<Primitive *> entityPrimitives
- A vector list of pointers to primitives belonging to entity.
- float x/y
- Location of entity.
- vector<Primitive *> entityPrimitives
- BasicEnemy extends GameEntity
- Description: This class contains methods that are common to all enemies.
- Public
- void doDamage(int hitPoints)
- Called when enemy is hit by a weapon.
- bool isAlive()
- Called to see if enemy has been destroyed.
- void doDamage(int hitPoints)
- Private
- int hitPoints
- The amount of damage that is required to kill this enemy.
- int hitPoints
There will be a few different types of enemies but we have not yet fleshed out the enemy types.
- Tower extends GameEntity
- Description: This class contains methods common to all offensive towers. This is an abstract class.
- Public
- virtual int getHitPoints(BasicEnemy enemy)
- Returns the amount of damage this tower will inflict on a given enemy.
- virtual int getHitPoints(BasicEnemy enemy)
Each tower will contain at least one GameEntity object that contains its weapon primitives (such as a laser beam or a moving missile).
- LaserTower extends Tower
- Description: This class contains a tower that shoots a laser beam.
- MissileTower extends Tower
- Description: This class contains a tower that shoots a missle.
- Map extends GameEntity
- Description: Maintains information about the current map, such as grid locations, enemy paths, and player turret locations.
- Public
- enum Difficulty {BEGINNER, INTERMEDIATE, ADVANCED}
- Possible difficulties that a map may have.
- bool loadMap(char *name)
- Attempts to load the given map name.
- void sendEnemyOnPath(BasicEnemy *enemy)
- Starts the enemy on the predetermined path that all enemies take.
- enum Difficulty {BEGINNER, INTERMEDIATE, ADVANCED}
- Private
- Map::Difficulty difficulty
- The difficulty level of the map.
- char[][] grid
- This is a 2-D representation of the map grid. Different values stored in this array represent things like places for turret locations, enemy paths, etc.
- Map::Difficulty difficulty
- DirectInput
- Description: This class contains methods for retrieving information regarding input device state.
- Public
- Point getMousePosition()
- Returns the current X/Y coordinates of the mouse pointer (can be sent to Map entity to translate to map grid X/Y coordinates).
- byte *getKeyState()
- Returns a pointer to a 255 byte array containing the state of all keys.
- Point getMousePosition()
- Private
- Various DirectInput handles.
- GameManager
- Description: This class maintains the state of the game. It contains a timer that fires at predetermined intervals to update game logic in a predictable fashion.
- Public
- void init()
- Creates a thread for the GameManager and initializes timer object.
- bool addEntity(GameEntity *entity)
- Adds an entity to the list of entities that should be drawn by the GameRenderer.
- vector<GameEntity *> *getGameEntities()
- Returns a pointer to the vector containing all game entities that should be drawn to the screen.
- bool isPaused()
- Returns paused status.
- void updateGameState()
- Called by the timer at a predetermined interval, this is the main game logic method that updates the state of the game.
- void init()
- Private
- vector<GameEntity *> gameEntities
- Contains all game entities that should be drawn to the screen.
- Timer timer
- This contains a timer object that updates game logic at predetermined intervals.
- vector<GameEntity *> gameEntities
- GameRenderer
- Description: This class draws all game entities.
- Public
- Misc. Direct3D handles.
- bool initRenderer()
- Calls private methods for initializing the renderer.
- GameRenderer& getInstance()
- Returns the singleton GameRenderer object.
- Private
- bool initD3D()
- Initialized Direct3D
- void render()
- Sets up Direct3D for rendering the next frame, draws all entities (retrieved from GameManager), then displays frame.
- bool initD3D()
- Score
- Description: This class allows the game to submit high score information to a centralized database.
- Public
- static bool SubmitScore(TCHAR *name, unsigned int64 score)
- Attempts to submit high score to web service.
- static bool SubmitScore(TCHAR *name, unsigned int64 score)
- Private
- static bool MD5(TCHAR *source, TCHAR *dest)
- Generates an MD5 hash of source and places it into dest.
- static bool MD5(TCHAR *source, TCHAR *dest)
- HFBTowerDefense
- Description: This is the entry point of the application.
- void _tmain()
- Initializes GameManager and GameRenderer threads and begins execution of both.
7. Appendices
Not Applicable.
