Functionality
The classes that are used to run the Data Manager are essentially
used as standard vectors, but they have added features.
The added features are saving and loading using text files,
error checking, and code generation for easier use and
maintenance of the Data Manager. The Data Manager uses several
helper functions to run these features. When data is loaded in from a file using the
Data Manager, a name and description is also loaded in.
The name is so that the user of the Data Manager will have an easier
time using the correct data, and the description is so that
user, or anyone else, can be reminded of the purpose of the
variable. The base class of my
Data Manager is Global.
When a Global object is made it calls the function Add_to_Global_list, and passes in a pointer
of itself.
The passed in pointer is then stored in a vector of pointers that the
other helper functions will use. When ResetGlobals
is called, it uses the vector of Global pointers to clear out
all of the data stored in the Globals, and then it calls the Global's
Load function, to reset all of their data. This lets
the user change the data in the script, and have it loaded
in without having to close the exe and open it up again. When DumpGlobals is
called, it uses the vector of Global pointers to have all of the Globals save their data to a text file, so that the current
state of the game can be examined for debugging.
CreateEnumFiles takes
the names of the variables to generate enums, and it creates header and
source files to load in those enums from a text file.
An example use for this function is that I use this function to make several different types of physics
objects, such as a bouncy ball or a box, and I have another
Global load in different data, one of which is a parameter
for which type of physics object to use.
In my current project, ResetGlobals and DumpGlobals
are called whenever their corresponding buttons are pressed
on the keyboard. This will be taken out before the
final version of the game, but for now it makes it easy to
change the text file, and instantly load in the changes. CreateEnumFiles
isn't mapped to any keys, because that would cause a change
in code, and make the project recompile, so I made an exe
that I call, and all it does is update the enum files.
To make sure no enums are the same, all of the names for
every variable is copied to a vector when they are made, and
the vector is checked to make sure it doesn't have any
duplicate names. This slows down loading if enough
variables are made. This and other error checks can be
removed from the game by commenting out a single #define,
which would be done sometime before the final version of the
game.
Class Hierarchy
Below I have a UML showing the classes used in my Data
Manager,
their variables, and a some of their functions. The
classes have other functions, but these are the important
ones. Global is a pure virtual class,
which
is inherited by the other classes. Save(), Load(), DumpData(), and GenEnumFiles() are all virtual functions.
The Classes
The Global class is used mostly so all of
the helper functions (described above) can easily call on
the classes that inherit the Global class.
The class, GenericGlobal, is a templated
class. GenericGlobal is a wrapper around the standard
vector, and gives it all of the benefits of scripting.
If a certain data type is to use GenericGlobal, it is required for
that data type to have a Save and Load
function.
The Save and Load functions aren't supposed to be member
functions, but rather functions that take in the data type as a parameter, ie. Save(ofstream &out, DataType &dt) Load(ifstream
&in, DataType &dt). Having the save and load
functions written this way, it allows for saving and loading
for data types that you can't add member functions.
GenericGlobal is templated, and can handle
any data type, so why have the ConstGlobal class? Just
from looking at the diagram above it looks a bit redundant,
and a bit messy right? The reason for that is because
this class is meant to hold all of the constants for a given
engine, ie gravity for physics. These values tend to
be played with to find what looks best, and may be changed
for special effects, which is very important for my current
game. By having ConstGlobal, it keeps the data more
centralized, and it keeps the number of files needed at a
minimum. Without it the user would have to create a
new file and Global for each of the 5 different data types,
and makes it messier in the end, by having too many files. One of the main ideas that I followed when
writing my script was to keep similar data grouped
together, and even though they are different data types,
they are all a random assortment of values to make a given
engine run. The other part of this is if, for example,
I need to disable certain features in the Graphics engine,
so I can run the game on my home computer, I can just go and
edit a bool in the script, instead of going into someone
else's code and search for what I need to change to turn it off, and having all the data in one
file makes it easier for other users to find.
The ObjectManager was written by a teammate,
and its purpose is to localize and maintain all of the
objects it the game. By objects I mean the player,
enemies, trees, rocks, ect. After my teammate made
this class, I made the class inherit the Global class and
wrote it's Save and Load functions, so it
now has all the features of the Global class, and all that I need
to do is maintain the Save and Load functions as new data is
added to the objects. By having the Data Manager also
manage the objects in the game, it made it really easy to
make a Level Editor later on.
Member functions
The save and load functions are self
explanatory, but each class needs its own version since they
all handle saving and loading rather differently.
DumpData
takes in an ofstream and saves all of it's data to it, along
with the file name and the enums that are used to index the
data stored in the Global objects.
GenEnumFiles
creates a header file for every global object, and in that
header file is written an enum, which is used to access the
data stored in the Global. In the header file GenEnumFiles
also writes the save and load functions for the previously made enum,
and functions to convert the enum to a string or a string to
the enum.
The last function, GetData, takes in an
enum, and returns the desired data. The ConstGlobal
class actually has 5 different versions of GetData, one for
each data type.
DOWNLOAD DATA
MANAGER
|