-
Notifications
You must be signed in to change notification settings - Fork 8
components
In this document I will discuss the workings of the component system, as well as provide a tutorial and code samples to help you create your own components. The tutorial is for the beginnings of a stat system, which you can feel free to use; it also highlights more advanced features, which should make it easier to understand the basics. (Tutorial is todo).
Components provide a method to perform object composition on the fly and dynamically in the game, which can be extended to the script engine, or used in various other places to easily add and remove behavior from objects.
Components provide a has-a relationship for objects; you can start with a basic Entity object and add behavior.
think of components as containing specific types of behavior. You may decide to add a clothing, container and weapon component, but you wouldn't want every object to inherit all of these; instead, you can provide this functionality through individual components, and allow builders and scripters to add these to your object. This means that a weapon could be a container and a weapon, but doesn't have to be worn, or that a backpack could include clothing and container, for example.
Components have two distinct pieces; the component object itself, and the component meta object. The Component Meta object exists as a placeholder for individual components. It contains information on what each component is, including, but not limited to the name and required dependencies for the component which it manages. While this provides an easy mechenism for grouping and managing types of components, it also serves to cut down on the memory footprint by alleviating the cost of storing a list of dependencies and name for each loaded component, along with any other information that will be shared across components of specific types in the future.
Component meta objects also have an interface, IComponentMeta
which you can use to define your own versions of these objects. Unless you have a specific reason to do so, I recommend that you inherit the ComponentMeta
class and instanciate the template to add extra features to individual ComponentMeta
objects.
The Component
object is where all of the logic will be held for that specific component. You will likely want to inherit the Component
object and extend this with your functionality. The Component
object manages and maintains references to the object which it is attached to; you can think of the relationship as a many to one from the object to the components.
The only caveat to extending the Component
object is that you need to make sure to call the constructor as with any other object, as there is work that takes place within the constructor itself.components also by default include a mechenism to register and call events as an EventManager
as well as a storage system for properties which will be serialized with the component objects themselves.
As previously mentioned, the Component
object is used to hold information specific to individual components, while the Componentmeta
object holds information specific to individual components under them. this means that clothing, armor, weapons would all have their own ComponentMeta
from which components would be created.
the ComponentMeta
object is a templated object, meaning that you'll need to instanciate it with individual components. If you are simply writing a component that other logic will attach, you can simply use the base ComponentMeta
object. If you wish to add logic to the component itself (such as the component being added to a player or npc once it's created or logged in), you will need to create your own ComponentMeta
, specialize it with the component you've defined and add that logic.
In the World
object, there are two methods: RegisterComponent
and CreateComponent
which are simply wrappers to call the underlying ComponentFactory
object. the component factory holds a mapping of <std::string, IComponentMeta*>
. The key is the name of the component, and the value is a pointer to the ComponentMeta
object currently stored. When CreateComponent
is called, the Create
methond on the ComponentMeta
is called, which returns a new object of type T
, which is the type passed into the ComponentMeta
template. Each components has an Initialize
method which is called prior to the component being attached to any object, so it should not be assumed that the component is attached to a specific object. Any logic that needs to take place after the component is attached to an object should subscribe to the events on the component itself.
Created components through World::CreateComponent
will not be attached to an object; it is up to the user to call AddComponent
on the object to which they want to add the component.
When the object's AddComponent is called, and assuming that the object already does not have a component by the same name, dependencies from the component meta are traversed and added. The Attach
method on components is not virtual and should not be overridden; use events for this purpose.