38
Mypos Games – An Auspicious Adventure – Technical Design Document
Mypos Games Presents: An Auspicious Adventure
Technical Design Document
© 2002 Jonathan Stern, Tech. Dir., Mypos Games
GAM200
Summer 2002
Team 3
1 System Information 5
1.1 Target Platform 5
1.2 Minimum System Requirements 5
2 Coding Standards 5
2.1 Comments 5
2.2 File Structure 5
2.3 Header File Structure 6
2.4 CPP Module Structure 6
2.5 Global Constants 6
2.6 Variables and Parameters 7
2.7 Additional notes for pointers 7
2.8 Pointers vs. References 7
2.9 Global Variables 8
2.10 Functions and Methods 8
2.11 Classes 8
2.12 Structs 8
2.13 Functions 9
2.14 Whitespace, Indenting, and Braces 9
2.15 Breaking Statements up onto Multiple Lines 10
2.16 Whitespace 11
2.17 Preprocessor Use 12
3 Windows Application Setup and Main Message Loop 12
3.1 Generating Enemy A.I. 13
3.2 Obtaining User Input 13
3.3 Updating the Display 13
4 Display 13
4.1 Display Modes 13
4.2 Initializing the Display: The Display Class 14
4.3 Initializing DirectDraw 15
4.4 Initializing the Primary Surface 15
4.5 Initializing the Display at Startup 15
4.6 Changing the Display Mode in Mid-Game 15
4.7 The DisplaySurface Class 16
4.8 Rendering Bitmap Files to DirectDraw Surfaces 16
4.9 Checking for Surface Loss 17
4.10 Rendering to the Back Buffer and the Primary Surface 18
4.11 Updating the Game Display 19
4.12 Parallax Layers 19
4.13 Rendering the Sprites 20
4.14 DirectDraw Cleanup 20
5 Title Screen and Menus 20
5.1 Menus 21
5.2 Character Select 22
6 Game Mechanics 22
6.1 Game World Perspective 22
6.2 Coordinate System 22
6.3 Scrolling 23
6.4 The Camera 23
6.5 Movement Boundaries and the Yon Wall 23
6.6 Game Timer 24
6.7 Pausing the Game 24
7 Sprites, Animations, and Actions 25
7.1 Animation Sets 25
7.2 Animation Frames 25
7.3 Actions 26
7.4 Sprites 27
7.5 Sentient Object Class 29
7.6 Player Class 29
7.7 Enemy Class 33
7.8 Acquirable Items 35
7.9 Projectiles 36
8 Sentient Object Movement and Attacks 37
8.1 Walking 37
8.2 Dashing 37
8.3 Jumping 37
8.4 Combo System 37
8.5 Dashing Attacks 37
8.6 Jumping and Jumping Attacks 38
8.7 Damage, Knockback, and Knockdown 38
9 Collision Detection 38
9.1 Attack Collision 38
9.2 Picking Up Items 40
10 Maps and Tiles 40
10.1 Maps 40
10.2 Tiles 40
10.3 Map Class 40
10.4 Objects on the Map 41
10.5 Map File Format 41
10.6 Map Zones 41
10.7 Items on the Map 42
11 Heads-Up-Display 42
11.1 The HUD Class 42
12 User Input 43
12.1 Keyboard Input and The Input Class 43
12.2 Processing Player Input 44
12.3 Unmappable Keyboard Keys 47
12.4 Keyboard Input in Menus 47
12.5 Mouse Input 47
12.6 Input Cleanup 47
13 Artificial Intelligence 47
13.1 The Enemy AIAttack Struct 48
13.2 Generating Enemy AI Actions 48
14 Sound 48
14.1 The Sound System class 48
14.2 The SoundBuffer class 49
15 Asset Memory Management and File Formats 50
15.1 File Formats 50
15.2 Data Script Files 50
15.3 Memory Management 50
15.4 Initializing Play 50
15.5 Memory Allocation 51
15.6 Parsing the Script Files 51
15.7 Bitmap Script File 52
15.8 Sound Script File 52
15.9 Animset Script File 52
15.10 Player Script File 53
15.11 Enemy Script File 53
15.12 Projectile Script File 53
15.13 Item Script File 53
15.14 Memory Cleanup 54
16 Loading and Saving User Data 54
16.1 User Game Progress 54
16.2 User Configuration Data 54
17 Message Logging 54
17.1 The Log Class 54
18 Miscellaneous Data Structures 55
18.1 String Class 55
18.2 Linked List Class 55
19 Memory Map 57
1 System Information
1.1 Target Platform
IBM compatibles running Windows 9x, Windows 2000, or Windows XP.
1.2 Minimum System Requirements
· Windows 95/98/ME/XP/2000
· 64 megs of system RAM
· Pentium II 300 MHz or better
· 30 MB free disk space
· DirectX 7
· 4MB video card
· Keyboard
2 Coding Standards
In order to maintain consistency and readability among files in the project, certain standards shall be adopted.
2.1 Comments
Use C++-style comments (preceded by ‘//’) whenever possible. C-style comments (/* … */) can be used to comment out blocks of code, but they should be applied minimally as they do not generally nest.
2.2 File Structure
Names of files in the project should follow the same nomenclature applied to function names (see below). At the top of each source code file in the project (both .h and .cpp), the following header must be included:
//======
// Filename -
// Purpose -
// Creator -
// Date Started -
// Last Updated -
//======
2.3 Header File Structure
The following structure will be adopted for header files. <Module Name> corresponds to the name of the file (sans the ‘.h’ extension) and should be in all caps in the preprocessor definition. Note that the order of the separate sections should be followed as a general guideline but can be altered as necessary. Additional sections can be added as needed.
#ifndef <Module Name>_H
#define <Module Name>_H
//=== Includes ======
//=== Enumerated Set Definitions ======
//=== Constants ======
//=== Macros ======
//=== Global Variables ======
//=== Global Function Declarations ======
//=== Class Function Definitions ======
//=== Class, Struct and Union Declarations ======
#endif // <Module Name>_H
2.4 CPP Module Structure
CPP modules should make use of the following structure. Again, the order of the separate sections should be followed as a general guideline but can be altered as necessary.
//=== Includes ======
//=== Enumerated Set Definitions ======
//=== Constants ======
//=== Macros ======
//=== Global Variables ======
//=== Global Function Definitions ======
//=== Class Function Definitions ======
2.5 Global Constants
Use all upper case letters. Concatenate “words” with an underscore. Prefixes are not necessary.
Example: const DWORD SCREEN_WIDTH = 640;
2.6 Variables and Parameters
Start with a lower case letter. Concatenate “words” with an upper case letter. In addition, the following prefixes should be used, in compliance with Hungarian Notation (from Programming Windows, Petzold):
c char or WCHAR or TCHAR
by BYTE (unsigned char)
n short
i int
x, y, z int used as x-, y-, or z-coordinates
cx, cy int used as x or y length; c stands for "count"
b or f bool (int); f stands for "flag"
w WORD (unsigned short)
l LONG (long)
dw DWORD (unsigned long)
s string
sz string terminated by 0 character
h handle
p pointer
Simple integers and floating point numbers will not require a prefix. When defining variables, align the types, the names, and the initial values (aligned on the equal sign) of the variables each in separate columns. For example:
int iMyInt = 6;
bool bMyBool = false;
DWORD dwMyDword = 0xA000;
2.7 Additional notes for pointers
With the p prefix for pointers, additional prefixes are not necessary (e.g., you do not need to use pdwMyDword for a pointer to a DWORD), unless it is a pointer to a pointer, in which case pp should be used instead. Additionally, if the pointer points to a byte, pb can be used instead of pby if so desired.
When defining a pointer variable, use a space both before and after the asterisk. If the variable is a pointer to a pointer, the two asterisks need not be separated (e.g. MyStruct ** ppMyStructInstance).
2.8 Pointers vs. References
Use pointers instead of references for sake of clarity, unless you have good reason or they are necessary in class methods parameters. Above all, try to remain consistent.
2.9 Global Variables
Prefix all globals with g_ (‘g’ followed by an underscore). After the underscore, apply the same rules for regular variables.
Example: DWORD * g_pdwMyDword;
2.10 Functions and Methods
Start with an upper case letter. Concatenate “words” with an upper case letter.
Example: void MyFunc( void );
2.11 Classes
Classes will be preceded by the following comment heading:
//======
// Class - CClassName
// Purpose –
// Creator -
//======
Class names will be prefixed by a capital ‘C’, after which the same rules for functions and methods are applied. Use an m_ (‘m’ followed by an underscore) prefix for all member variables.
Example: class CSprite {…};
2.12 Structs
Structs will be preceded by the following comment heading:
//======
// Struct - StructName
// Purpose –
// Creator -
//======
Struct names follow the same fules for functions and methods. When using ‘typedef struct,’ use the following format:
typedef struct tMyStruct
{
int memberVariable;
} MyStruct, * PMYSTRUCT;
In C++ this format is not necessary since the compiler tags struct definitions anyway. Unlike classes, member variables of structs do not need the m_ prefix.
2.13 Functions
The prototype for each function should have a short one-line (or possibly longer) comment above it. If desired, prototypes for several related functions can be grouped together under one comment.
// Descriptive comment
void MyFunc( char * input1, int input2 );
The definition of a function will be proceeded by a function header as demonstrated below. On the first line should be the return type followed by the name. Then there are two options for the parameter list: if there are few parameters, put them all on the same line; if there are many, put the opening parenthesis on the next line, then give each parameter its own line, indented as if a block of code. Then close the parentheses on the next line, followed by the body of the function. Try to keep the number of returns in the code to a minimum.
//======
// Function - Name of function
// Purpose -
// Creator -
// Inputs - pInput1: array of items
// dwInput2: number of items in array
// etc.
// Return -
//======
void MyFunc
(
char * pInput1,
DWORD dwInput2
)
{
.
.
.
}
2.14 Whitespace, Indenting, and Braces
Indents should all be four spaces and use the actual space character rather than tabs. For if statements and for and while loops, the opening brace should go on its own line immediately following the initial statement, aligned with that statement; the body of the loop or if statement should be indented. Enumeration and structure definitions should follow a similar format, although if an enumerated set is short enough, it can go all on one line. With classes, indent once for the ‘public:’ and ‘private:’ section headings, and again for the member variables or method prototypes. If an if statement or loop has only one line in its body, that line need not be in braces, but it should be indented and on the next line. In addition, try to avoid leaving extraneous whitespace at the end of lines.
Examples:
if ( condition )
{
.
.
}
while ( condition )
{
.
.
}
enum State { ALIVE, DEAD };
enum Color
{
RED,
GREEN,
BLUE,
YELLOW,
NUM_COLORS
};
class CMyClass
{
public:
CMyClass();
int MyMethod( int nParam );
private:
LONG lMemberVariable;
};
With switch statements, use the following format:
switch (msg)
{
case SOME_CASE:
DoSomething();
break;
case SOME_OTHER_CASE:
{
// Using local variables
int nMyVar;
DoSomethingElse(nMyVar);
break;
}
default:
break;
}
2.15 Breaking Statements up onto Multiple Lines
The following comes from the code standards established for CS120 in the Fall of 2001.
When a statement extends beyond the end of the line, break it at an appropriate place and fit it onto two or more lines in a way that maintains the current indentation level. In an "if" construct with multiple conditions, align the conditional expressions if they require more than one line:
if ( ( numberOfFiles < totalNumberOfFiles ) &
( status == true ) )
{
}
If a function call requires more than one line, group the arguments and, where possible, align them vertically with the first formal argument in the list; otherwise, indent the first argument on each succeeding line one level from the beginning of the function name:
bool bRet = Function( servers, NULL,
numberOfServers, done );
For functions with many formal arguments or arguments that require explanation, put each argument on a separate line (useful when using a very unfamiliar and complicated function), followed by a comment:
bool bRet = Function( servers,
NULL,
numberOfServers,
done );
2.16 Whitespace
The following comes from the code standards established for CS120 in the Fall of 2001.
There should be no space between a unary operator and its operand:
--count;
++numberOfFilesOpen;
Leave at least one space between a binary operator and each of its operands; use extra spaces to align operands if this improves readability:
x = y;
min = -max;
letter = *pDrive;
x += y;
( pItem->GetID() == id ) & ( status == true ) )
Function calls should not have a space between the statement and the associated parenthesized expression. Thus,
if ( status == true )
{
DoThing( status );
}
Formal arguments in a function call should be preceded by a single space and followed immediately by a comma, except for the final argument which is followed by a space:
bool bRet = MyFunction( servers, NULL );
2.17 Preprocessor Use
Use typedefs and global constants instead of preprocessor #defines whenever possible. Names of preprocessor-#defined macros should follow the same nomenclature as for global constants (all caps, underscores to separate “words”).
When using preprocessor #ifs to set aside a block of code, align the preprocessor statements as if they were normal code, and indent the code inside. For example:
void ProcessMap( const char * szMapName )
{
char * pMap;
if ( NULL != szMapName )
{
bool bSuccess = false;
# if defined( PALM_OS )
bSuccess = ReadMapFromDatabase( &pMap, szMapName,
&g_hMapHandle );
# elif defined( MAC_OS )
bSuccess = ReadMapFromResource( &pMap, szMapName,
&g_hResourceID );
# else // Using Windows
bSuccess = ReadMapFromFile( &pMap, szMapName );
# endif
DoStuffWithMap( pMap );
}