Author Topic:   How Tread Marks' Entity Architecture works
LDA Seumas
posted September 03, 1999 05:55 AM           
I just sent this off to the Software-Engineering-Game-Design mailing list, but thought it would be worth re-posting here as well, for those who are interested. Feel free to comment or ask questions, as I've left out some important details.

In my system, I have the Actors ("Entities", which are basically everything in the game) the Masters of All, with fairly light weight RenderObject objects contained within each Entity object which are added to a queue in a PolyRender mega-object and told to virtually draw themselves (which is where OpenGL is called, etc.) once all Entity thinking is done.

My Entities are very Data Driven. I split things into "Entity Classes" and "Entity Types". Entity Classes are the actual C++ classes with code to make a specific type of Entity do what it does. Classes include things like "RaceTank", "Smoke", "Explosion", "Weapon", "Projectile", "Sound", "God" (handles global housekeeping), etc. Each Class has a large number of modifiable parameters, not the least of which are their Mesh/Image/Sound files, plus other things such as speed, behavior flags, life span, etc. None of these parameters are hard-coded, and are all loaded from textual configuration files. Each config file defines an Entity Type, which specifies an Entity Class name, the name of this Entity Type within the class, and a list of parameter key/value pairs that make this type special.

In the code, this is handled with two C++ classes per Entity Class, an e.g. EntityRacetankType class, which inherits from EntityTypeBase (or a child of it), and an e.g. EntityRacetank class, which inherits from EntityBase. When an object of EntityRacetankType is instantiated, it has handle to a config file passed in which it reads its special parameters from. To create an object of class EntityRacetank (to actually put a Racing Tank in the game), you ask one of the previously instantiated EntityRacetankType objects to manufacture an EntityRacetank object. That EntityRacetank object is associated with the parameters and resource files of its Type through a back-pointer to the EntityRacetankType object that manufactured it. Thus, Entity objects hold no resources themselves, and merely hold what is essentially a VirtualResourceAndParameterStructurePointer; the EntityTypeBase derived objects actually load the image/sound/mesh resources.

To make things even more abstract, each compilation unit that defines new Entity classes has a special factory function to manufacture an EntityTypeBase derived object based on a passed in Config File. That function reads the Class Name and Type Name from the config file, and if the Class Name matches a Class it (the compilation unit) provides C++ code for, it instantiates said object using said config file and passes a pointer back. If it doesn't handle the Class in the config file, it returns zero. Now, at the start of the app, another function in each Entity compilation is called to Register that compilation unit's (or DLL, if/when I break it all into DLLs) Creation function, which calls a global Entity API function to add its Creation function to a global list of Entity Type Creation Function Pointers. Now, when the game enumerates all the Entity config files on disk, it calls the global Entity API Create Type Object with each config file. That function in turn calls all the registered Creation functions until it gets an object back. If they all fail, that means the Entity Class specified in the config file does not exist as C++ code in the program.

After the above, the app has a nice linked list of EntityTypeBase derived objects which each specify parameters and resource files/handles for a unique EntityClass/EntityType pair. To create a specific EntityBase derived object to add a new entity to the game, the EntityTypeBase object list is walked until a Class/Type match is found, and that object is then told to create an EntityBase derived object of its specific Class/Type combo. A new Entity enters the game world, with the game world itself required to know practically nothing about what the entity is or what it does.

-- Seumas McNally, Lead Programmer, Longbow Digital Arts