Placing
Characters on the Map
While going through the
examples, I placed characters on the map in
a direct, hard-coded manner. However, remember that hard-coding game data is a
no-no. You need to have as much flexibility as possible when designing your
maps,
and this includes placement of characters in a level.
Two methods for placing
characters in maps that provide the flexibility you want
involve character map lists and scripts.
Character Map
Lists
In numerous chapters,
“Implementing Scripts,” I use external
data files that store a list of numbers and text. Those data files are loaded
and
parsed into some useful information to the engine loading the data. Action
templates,
for example, contain the action text plus the entry data for each action, all
in one easy-to-read-and-edit file.
To adhere to the simple nature
of using text data files, you can create lists of characters
to place within a map when the map is loaded. Because players are placed in
a map using only a set of coordinates and a direction to face, this data file
might
look something like the following:
0 100.0 0.0 450.0 0.0
21 0.0 0.0 -82.0 1.57
18 640.0 10.0 0.0 3.14
At first appearance, the
preceding three lines of numbers are just that—a list of
numbers—but the trained eye sees that each number represents something. Starting
with the first number on each line, you have the following:
■ The character’s type (for
example: 0=Main Character, 21=Ogre, 18=Child)
■ The X-coordinate, Y-coordinate, and Z-coordinate
■ The angle that the character is facing (in radians)
Now knowing what each number
means, you can see that I defined three characters
and placed them through the map at their respective locations and pointed
them in a certain direction. This data is compact, easy to edit, and can be
loaded
and processed quickly.
Loading Character Map Lists
To process the data files as
just described, you need only two functions.
These functions are as follows:
long get_next_long_2(FILE* fp)
{
char buf[1024];
long pos = 0;
for(;;)
{
int c = fgetc(fp);
if(c == EOF || c == '\n' || (c == ' ' && pos) || pos == sizeof(buf)-1)
break;
if((c >= '0' && c <= '9') || c == '.' || c == '-')
buf[pos++] = (char)c;
}
if(pos == 0) // if there is no long value in file
return -1;
buf[pos] = 0;
return atol(buf);
}
/////////////////////////////////////////////////////////////////////////////////////////////
float get_next_float_2(FILE* fp)
{
char buf[1024];
long pos = 0;
for(;;)
{
int c = fgetc(fp);
if(c == EOF || c == '\n' || (c == ' ' && pos) || pos == sizeof(buf)-1)
break;
if((c >= '0' && c <= '9') || c == '.' || c == '-')
buf[pos++] = (char)c;
}
buf[pos] = 0;
return (float)atof(buf);
}
Both functions take a file pointer
(fp) as an argument and return the next long type
number or float type number found in the specified file. You arrange the
character
map list data file so that the first number (the character type) is a long,
although
the remaining numbers are float.
Using
get_next_long_2 and
get_next_float_2, you can
parse an entire character map list as follows:
// fp =
file pointer to open character map data file
long Type; // Character type to load
float XPos, YPos, ZPos, Direction;
long NumCharactersLoaded = 0; // # characters loaded
while(1)
{
// Break if no more characters to process
if((Type = get_next_long_2 (fp)) == -1)
break;
// Get coordinates and angle
XPos = get_next_float_2(fp);
YPos = get_next_float_2(fp);
ZPos = get_next_float_2(fp);
Direction = get_next_float_2(fp);
// Do something with data - insert a character
NumCharactersLoaded++; // Increase # characters loaded
}
// Done loading NumCharactersLoaded # of characters