Sign in to follow this  

Component-based entity definition design

This topic is 3738 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm hammering out my component-based entity definition system. Here's my design so far. I'm posting it to get feedback, and I thought it could be informative to others planning something similar. Entities are component-based. The entity class has only a few basic properties: position and rotation (this is a 2D game), and entity type name. The rest of the entity is composed of components instantiated on a per-entity basis (e.g., render component, collision component, AI component, etc.). All are optional. The entity keeps the components in a map by component type name ("render", "AI", etc.). Each type of component also has a subsystem to create and manage those components (e.g., a collision component subsystem, etc.), and the subsystem keeps track of all instances of that component type (credit to Sneftel for that idea). What I'd like to discuss is the entity definition data, used when instantiating a type of entity to create and initialize its components. First of all, a there's a generic PropertiesDefinition class. It contains a list of named properties. A named property can be a string, a number, or a pointer to another PropertiesDefinition. An EntityDefinition is (or maybe has) a PropertiesDefinition. Its list of named properties always contains one property named "Components" that points to another PropertiesDefinition. The other (optional) properties in EntityDefinition are all strings or numbers, and are user-defined parameter variables (I'll explain that in a bit). The "Components" PropertiesDefinition defines, obviously, the components to be created for the entity. Each property it contains is named for the component type (e.g., "render"), and points to another PropertiesDefinition (of course) which contains all of the property values the component subsystem needs to create and initialize a component. An example EntityDefinition hierarchy might look something like this (in pseudo-data):
"size" = 27.3
"someOtherUserParam" = "hello"
"Components" =
	"render" =
		"spriteImage" = "funkyspaceship.png"
		"spriteSize" = ref("size")
	"collision" =
		"collisionShape" = "square"
		"collisionSize" = ref("size")
	"foobar" =
		"blah" = "asdfasd"
		"someNestedProperties" =
			"moreBlah" = 5
			"evenMore" = 7
This object is passed to each of the subsystems in turn. The subsystem checks to see if "Components" contains a component property for it (e.g., render system checks for a property named "render"). If there, it instantiates a component, and uses the contained properties to initialize it. Any of these values could actually be a reference to another definition object, so components can have nested sub-components or whatever they need (like "foobar" in the example). Any of the property values can be a reference to a user-defined parameter variable, like "size" in the example. You can see how this can be useful. The render component and the collision component both need a size specified. Rather than have one get the size from the other (and therefore depend on each other), a user-defined variable can be specified, and they can both refer to that. Also, whenever an entity is created using an EntityDefinition object, you could optionally specify values for any user variables, and these values would override the default values specified in the definition. So you could, for example, procedurally create (or have a script create) a bunch of entities from the definition above, but give them all different sizes. In the next post, I'll describe how these definitions are loaded from XML, in such a way that a definition can inherit from another definition (and selectively add to or override parts of it).

Share this post


Link to post
Share on other sites
The way the definitions are stored and loaded from xml files should be pretty obvious, since we'll just have a hierarchy of xml nodes that reflects the hierarchy of PropertiesDefinitions. An xml file for the example given before would look like this:

<entityDefinition name="FunkyShip" extends="BasicShip">
<property name="size" value="27.3" />
<property name="someOtherUserParam" value="hello" />
<property name="Components">
<property name="render" >
<property name="spriteImage" value="funkyspaceship.png" />
<property name="spriteSize" refValue="size" />
</property>
<property name="collision" >
<property name="collisionShape" value="square" />
<property name="collisionSize" refValue="size" />
</property>
<property name="foobar" >
<property name="blah" value="asdfasd" />
<property name="someNestedProperties">
<property name="moreBlah" value="5" />
<property name="evenMore" value=7 />
</property>
</property>
</property>
</entityDefinition>

The extends="BasicShip" part is how one entity definition inherits from another. We're assuming there's another entity definition named "BasicShip", either in this xml file or another one. When the "FunkyShip" EntityDefinition object is created, it will start with a copy of the "BasicShip" definition object, and modify that by overriding and/or adding. It can override components and their properties, and it can also override user-defined parameter variables (so you could have some sophisticated entity definition as a sort of template, and override it by just changing some of the variables).

All of the xml documents containing entity definitions are loaded in a batch into some DOM format (I'm using tinyXml), then they're all processed to create the EntityDefinition objects.

Each xml document is walked through. When an entityDefinition node is found, a pointer to the xml node is stored in a map by the name attribute (and the node isn't traversed any deeper at this point).

We then iterate through this map, calling MakeEntityDefinitionFromXML() for each one. This function creates an EntityDefinition object (with its hierarchy), and puts it in a different map by name (it first checks to see if it's already in the map, before creating it). If MakeEntityDefinitionFromXML() sees that the definition inherits from another one, it calls GetEntityDefinition() to get the definition object it inherits from, copies it, and builds on that. GetEntityDefinition() first checks the definition object map, and if it finds it, returns it. If not, it checks the xml node map (if it's not there, throw an error). It takes the node from the xml node map, recursively calls MakeEntityDefinitionFromXML(), and returns the result of that. I'll need to check for circular dependencies in there somewhere.

After all of the nodes in the xml node map have been processed, the xml node map is cleared, and all of the xml document objects can be destroyed.

So, any thoughts? Comments? Flames?

Share this post


Link to post
Share on other sites

This topic is 3738 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this