Game entity/component system - creation argument list

Started by
15 comments, last by Juliean 11 years, 1 month ago

Hello,

I've started implement an Entitiy-System as described in the first article, using an implementation as offered in the topmost answer in the second link:

http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php

http://gamedev.stackexchange.com/questions/17746/entity-component-systems-in-c-how-do-i-discover-types-and-construct-component

Works unexepectably well on the first shot, but what bugs me is this:


class Entity { 

void AttachComponent(ComponentType, argumentList, name)

...

}

That code snippet from Gamasutra shows a similar method that I implemented:


void Entity::AttachComponent(LPCSTR lpComponentType, LPCSTR lpName)
{
    Component* pComponent = component::create(lpComponentType); //get component by type
    m_mComponents[lpName] = pComponent; //register component from name
    m_mTypeComponents[lpComponentType].push_back(pComponent); //register component from type
}

Now there is one important detail left in comparison to the Gamastura-code: The argumentList. Obviously I am going to need to pass some sort of arguments to the component on creation, be it a pointer to the render-queue or the filename of the mesh I want to render. How would I implement that?

The only thing I really can think about is to change the method to something like this:


void Entity::AttachComponent(Component& component, LPCSTR lpComponentType, LPCSTR lpName)
{
    m_mComponents[lpName] = component; //register component from name
    m_mTypeComponents[lpComponentType].push_back(component); //register component from type
}

and then create the component outside of the entity, using its "startup/init/whatever" method to initialize it. But I don't really think this is a good approach, is it?

The other thing I had in mind is to make an "argumentList" - object, inheriting it for every component, passing it to its "startup"-method and therefore to the AttachComponent-method, creating it before calling it. The "arguments" would therefore be data members, and each component would need to cast the passed argumentList. Would that be a better approach?

If not, what else could/should I do?

Advertisement

If you can use C++11, you could use variadic templates and std::forward your arguments to constructor. If you can't you can still template arguments, though it will be a bit more work (you have to define templates for all possible numbers of arguments, or use some macro magic - with variadic templates its just one line of code).

And I don't think there is anything wrong with constructing component object outside and attaching it to entity - you may want to do some sort of pre-processing and set various information so why not do it this way? As long as you have clear state of ownership of such component it won't be a problem.


Where are we and when are we and who are we?
How many people in how many places at how many times?
The approach I have used before (and currently use, though in a language like Lua it is very easy to do, given the dynamically-typed nature of the language) is to use some sort of variant class. A variant is a data object that can hold anything. (within reason). That is, something like boost::any. Typically, I'll write my variants to be more specific than boost::any, though. For the argument list, I pass a map keyed on string of variant properties.

An example of this is the YAML-cpp library. When a YAML file is loaded, the elements are converted to variant types and stored in a nested tree structure. Using a library such as this as an intermediary makes it easy to load your argument list from a data file, then just pass the tree structure to your various factories to build components.

An example of this is the YAML-cpp library. When a YAML file is loaded, the elements are converted to variant types and stored in a nested tree structure. Using a library such as this as an intermediary makes it easy to load your argument list from a data file, then just pass the tree structure to your various factories to build components.


I've done something like this using JSON as the data format. An entity can be defined by a set of components, each with its own data, all stored in the same JSON object. The entire entity can then be constructed from the parsed object.

It is necessary to be able to create entities in code as well, since not all entities can be defined before the game starts. I don't see a problem with any of the above approaches.

You could also pass in a map object. The map object would contain all required inputs and the initialize function would just read the map object for the values it needs.



See example in the EntityX library how this can be done. It is C++11 based on variadic template arguments, which is a little difficult. But it also supports that you construct the component first, and then attach it.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

Thanks for all the answers!

If you can use C++11, you could use variadic templates and std::forward your arguments to constructor. If you can't you can still template arguments, though it will be a bit more work (you have to define templates for all possible numbers of arguments, or use some macro magic - with variadic templates its just one line of code).

The varidic templates definitily sounded interesting, but unfortunately they are not supported by Visual Studio 2012... If I were to write templates for all the possible number of arguments given, would I also need to overload the function for each of these templates (Arguments1<>, Arguments2<>, ...) or is there some way to templatize (is this a word) the templates so that I can have "Component::Component(Arguments args)" for me to pass as many arguments as I want?

And I don't think there is anything wrong with constructing component object outside and attaching it to entity - you may want to do some sort of pre-processing and set various information so why not do it this way? As long as you have clear state of ownership of such component it won't be a problem.

I'll pick that approach if I fail to implement something else, yet I still prefer the more "automated" approach since I've already got a pretty interface around it using a string to identify the component...

The approach I have used before (and currently use, though in a language like Lua it is very easy to do, given the dynamically-typed nature of the language) is to use some sort of variant class. A variant is a data object that can hold anything. (within reason). That is, something like boost::any. Typically, I'll write my variants to be more specific than boost::any, though. For the argument list, I pass a map keyed on string of variant properties.

Sounds interesting too, is there any guide/tutorial or sample code on how to implement a variant? I googled a bit but didn't find anything related to my problem.

As for the file format, thats not really what I am looking for right now, I'll consider it some other time, but for beginning I think I'll stay code only.

You could also pass in a map object. The map object would contain all required inputs and the initialize function would just read the map object for the values it needs.

Only problem is that the arguments need to be of different type - one (Model) might need a pointer to my RenderQueue, and Material-ID and a Filename, the other one (ParticleEmitter) might want itself a map of force-fields, and a bunch of parameters regarding the particle generation/handling. A map with variant types would do, but simple a map isn't the solution...

See example in the EntityX library how this can be done. It is C++11 based on variadic template arguments, which is a little difficult. But it also supports that you construct the component first, and then attach it.

Pretty cool, I'll have a closer look to see how they implemented it (though like I said, variadic templates aren't an option for me, unfortunately). Speaking of which, in your example, they define components like Position and Direction. I though more about having something like a WorldComponent, RenderComponent, PhysicsComponent ... Therefore, I would also apply logic to the components, and not rely completely on systems like EntityX does. From what I've read some people tend to use components just as data containers, while others prefer more components with more logic like I wanted to have. Is there any huge advantage/disadvantage from any of those approaches or is it more a thing of preferrence? What would you recommend me to do starting out?

Thanks for all the answers!

If you can use C++11, you could use variadic templates and std::forward your arguments to constructor. If you can't you can still template arguments, though it will be a bit more work (you have to define templates for all possible numbers of arguments, or use some macro magic - with variadic templates its just one line of code).

The varidic templates definitily sounded interesting, but unfortunately they are not supported by Visual Studio 2012... If I were to write templates for all the possible number of arguments given, would I also need to overload the function for each of these templates (Arguments1<>, Arguments2<>, ...) or is there some way to templatize (is this a word) the templates so that I can have "Component::Component(Arguments args)" for me to pass as many arguments as I want?

About MSVC2012 - it supports variadic templates and few more C++11 features when you install CTP_Nov2012 (http://www.microsoft.com/en-us/download/details.aspx?id=35515) toolset and set it in your project options. Its CTP so its for testing but I use it and it works without problems. IMO having variadic templates is worth it smile.png

If you want to pass it around with varied number of arguments, that will be hell lot of templating. I was thinking about making a component factory with varied number of arguments that are then passed to constructor, and this factory gives you component. Something like:


Component* comp = compFactory->CreateComponent(SPATIAL, arg1, arg2);
Component* comp = compFactory->CreateComponent(RENDERABLE, arg1);
Component* comp = compFactory->CreateComponent(COLLIDABLE, arg1, arg2, arg3); 

Above code could be achieved by templating factory function "CreateComponent" to support different numbers of arguments that are passed to constructor, but as I said without variadics its a bit of crazy template magic (check this article and source code for really nice factory implementation: http://archive.gamedev.net/archive/reference/articles/article2097.html)

This can happen on higher level than entity, in some class that creates entities out of components. Does entity really need to know how to construct components (and itself?) or it should be responsibility of class above entity, that picks needed components (probably out of templates later, so its more automated) and creates another instance of entity by attaching necessary components. In some Entity System implementations, there is no such thing as Entity class, but its just a tag or id under which certain components are glued together by some "EntitySystem/Manager".

In my implementation, I kept GameObject class but its only responsibility is to be a container of component pointers that also keeps a bitmask of what component types are attached to that entity (I use it as for very fast lookups, as such bitmask works like a key that you can latet bit-and against some mask of required components and quickly filter entites that meet these criteria).


Where are we and when are we and who are we?
How many people in how many places at how many times?

Sounds interesting too, is there any guide/tutorial or sample code on how to implement a variant? I googled a bit but didn't find anything related to my problem.

As for the file format, thats not really what I am looking for right now, I'll consider it some other time, but for beginning I think I'll stay code only.

YAML-cpp is sample code for how it is achieved, that's why I linked to it. You don't need to use a library to learn from it.

YAML-cpp is sample code for how it is achieved, that's why I linked to it. You don't need to use a library to learn from it.

Oh, my bad. Reading about JSON files in EWClays post actually before reading yours confused me from the real purpose of your link... I'll definitaley check it out, along with the variadic templates and decide which fits my need better afterwards

About MSVC2012 - it supports variadic templates and few more C++11 features when you install CTP_Nov2012 (http://www.microsoft.com/en-us/download/details.aspx?id=35515) toolset and set it in your project options. Its CTP so its for testing but I use it and it works without problems. IMO having variadic templates is worth it smile.png

Ah, that worked, thanks... so I've tried to implement it, but don't know how to go any further.


template<typename... args>
class Arguments {};

class Component
{
public:
    template<typename... Args>
    virtual void StartUp(Arguments<Args...>) = 0; //???
    virtual void Update(void) = 0;
    virtual void HandleMessage(const Message& message) = 0;
};
 

So what I tried to make as an "Argument" class the takes how much arguments are needed, which would then get passed to the StartUp()-Function (if in the Entity or somewhere else shouldn't matter for now...). Only problem is that I get this error:

1>t:\dark mountain engine\repo\editor\component.h(13): error C2898: 'void Component::StartUp(Arguments<args...>)' : member function templates cannot be virtual (Component.cpp)

Obviously I can't do what I wanted to achieve here (have a function that takes a variadic template and by overloading that function each component will then decide how to use the argumentes. Is there just some syntax thing I didn't do, or is this whole approach faulty? If so, could you give me a short code example of how I'd achieve that? (variadic) templates are fairly new to me, and most examples I found in the internet are (seem to be) dealing with complete different things than what I want to achieve here, or I probably just don't understand it well enough...

Thanks in advance!

Edit:

Does entity really need to know how to construct components (and itself?) or it should be responsibility of class above entity, that picks needed components (probably out of templates later, so its more automated) and creates another instance of entity by attaching necessary components.

Well the Entity wouldn't really construct the component. It would just request an component object and pass its "StartUp()"-function the parameters specified, and the component itself takes care of its construction.

This topic is closed to new replies.

Advertisement