James Chagaris  Game Programmer 15709 NE 53rd St
Redmond, WA 98052
201-923-1037
jchagari@digipen.edu

MAIN      PROJECTS     LEVEL EDITOR     DATA MANAGER     VIDEOS     EXECUTABLES     CODE SAMPLES     RESUME    

DOWNLOAD DATA MANAGER

Data Manager

     When I was finishing up my project last year, I already knew what game I was going to be working on this year.  I knew that what we wanted to do for this year's game required us to make the game data driven.  I looked into a couple of different existing file parsers and scripting languages, but then I decided to make my own file parser and Data Manager, because I haven't really made any tools before, and I wanted the experience of making a tool for others to use, and the experience of figuring out what I needed to do to make it as complete as possible.  I figured that the way my teammates would view the Data Manager was as if it was just a glorified wrapper for globals in the game, so I named the based class of the Data Manager "Global."

 

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  

Copyright 2008 DigiPen (USA) Corporation, all rights reserved