Component-Based Entity Question

Started by
7 comments, last by mazelle 14 years, 7 months ago
I am working on a little demo to implement a component-based entity class to learn more about it. I am to the point where I need to assemble my entities with their appropriate components. I have read a lot of the threads on these forums regarding this subject and I have decided to go with a system where there is a Manager class for the Components of a certain type. The Component will be registered with the Manager when it is created. For example, the PhysicsManager will manage all of the PhysicsComponent instances. What do you guys think the best way to register the Component with the Manager is at creation time? I am not a big fan of singletons so I would like to avoid that if possible. I thought about making the PhysicsManager have all static methods and a static vector of PhysicsComponent objects so that in the PhysicsComponent constructor I could call PhysicsManager::registerComponent. Another thought I had is to have PhysicsManager create the instance of PhysicsComponent. I would call PhysicsManager::createComponent to get an instance of PhysicsComponent. Can anyone give me some advice on how they have done it? [Edited by - dustin10 on September 9, 2009 4:11:45 PM]
Advertisement
I would choose the latter, since using a static is going to require a global instance of the physics manager, which really isn't much improvement over the singleton.

You should request the creation of the components from the manager. How ever you can make that work.. Or alternatively you can fully construct the entity and then pass it to your specialized registerer which looks for componts of a particular type and registers them with their specific manager instance.
Another option is to create your components via a component factory, and have the factory register them after you create it. This factory could even be the component manager. The factory would be injected as a dependency to anything that needed to create components.
Quote:Original post by Rycross
Another option is to create your components via a component factory, and have the factory register them after you create it. This factory could even be the component manager. The factory would be injected as a dependency to anything that needed to create components.


This is what I do more or less... I have an asset manager that allocates large blocks of each type (everything from cameras to particles emitters/lights). and stores each of them in mini hash's (some are less mini than others).

memory is preallocated and asset creation and deletion is easily isolated.

------------------------------

redwoodpixel.com

Another vote for the system-as-component-factory approach. The only problem is that the system has to be passed to everyone that makes components, but you can use an abstract interface for the system and the components. This cuts down on the dependencies needed to use a component or system. C++/C#ish pseudocode:
interface IGraphicsComponent;interface IGraphicsSystem{    //among other things...    IGraphicsComponent* CreateComponent(...);//in C++, I use a smart pointer instead};class RealGraphicsSystem implements IGraphicsSystem{    IGraphicsComponent* CreateComponent(...){        RealGraphicsComponent* comp = new RealGraphicsComponent(...);        //register it        return comp;    }};


Only the module that constructs the system has to depend on RealGraphicsSystem.
Quote:Original post by theOcelot
Another vote for the system-as-component-factory approach. The only problem is that the system has to be passed to everyone that makes components, but you can use an abstract interface for the system and the components. This cuts down on the dependencies needed to use a component or system. C++/C#ish pseudocode:*** Source Snippet Removed ***

Only the module that constructs the system has to depend on RealGraphicsSystem.


Using a system like this, I would still need a common IComponent interface correct? Then I would just make IGraphicsComponent inherit from IComponent?

[Edited by - dustin10 on September 10, 2009 7:35:21 PM]
Quote:Original post by dustin10
Quote:Original post by theOcelot
Another vote for the system-as-component-factory approach. The only problem is that the system has to be passed to everyone that makes components, but you can use an abstract interface for the system and the components. This cuts down on the dependencies needed to use a component or system. C++/C#ish pseudocode:*** Source Snippet Removed ***

Only the module that constructs the system has to depend on RealGraphicsSystem.


Using a system like this, I would still need a common IComponent interface correct? Then I would just make IGraphicsComponent inherit from IComponent?


Only if you want to store different kinds of components in the same container, like a std::vector<IComponent*>. Mine don't. I just store the pointers directly in the class.
class Entity{    //stuff    IRenderComponent::ptr rendercomp;//ptr is a member typedef for boost::shared_ptr<IRenderComponent>};


Bam. Of course, I'm not taking advantage of the full flexibility possible in a component based design, but I'm not trying to. I designed my architecture to allow me to migrate incrementally. I'm kind of straddling the fence right now.

Only pay for what you need.
Quote:Original post by dustin10
I am to the point where I need to assemble my entities with their appropriate components.


Component-based entity-centric systems are something I'm learning about, too. Your issue is interesting, I've been there before as well.

I created an early draft of a creation mechanism for entities and their components. It's still unfinished, though, and it has been a while since I've taken a look at it. But perhaps these thoughts may give you some more ideas. And perhaps someone can highlight possible issues. (btw, I won't be able to respond until next wednesday, just so nobody wonders why I'm not answering.)

Well. My draft looks like this: There is no way to create individual components "from the outside". There is no public write access. Instead, I intend to use a builder (see builder pattern), which returns entities to you, not components. It is responsible for creating entities and their components, and registering them. Additionally, the builder is responsible for destroying them. (So it's basically builder and un-builder. Is there a common term for that?)

You would tell the builder what kind of entity you'd like to have, and the builder would know which components such an entity needs and create and register the necessary ones accordingly. That of course isn't mutually exclusive to the managers or factories creating components. It could be a mechanism on top of that.

The idea behind this is, I would like to have a mechanism that can create entities of a specific type just as easily as it would be with a traditional, inheritance-based approach. With inheritance, you would define a type by inheriting desired properties from other base classes. You could then instanciate objects of that class pretty easily.
With the builder, it should get equally easy. You have to tell the builder which components a certain type has once. After that, you can just tell the builder to construct an object of that type.

The benefits I see are: You have one central "knowledge base" about types, so this knowlegde isn't potentially spread among different source files. Registering and un-registering is handled automatically. Additionally, the construction process may be error-prone in other ways. The construction order of the components may be relevant, for example when a component depends on another one. The builder will take care of that.

A downside is that the builder has to be relatively intelligent, and thus, complex. That may or may not be easy to accomplish. Another downside may be "morphing" entities by changing their components becomes difficult. Since there is no access to the components, you can't easily replace, add or remove them. This would also have to be done via the builder, which means additional complexity. I think I'd implement that only if I really needed that feature.
I implemented it this way:

I implemented a component manager that can handle any class types as long as they implement IComponent and is default constructible (I mean the manager returns pointers/references of the class type, not IComponent).

I also have a factory for component managers. So when it comes to component creation time, this is what it looks like:

PhysicsComponent* const newComponent = componentManagerFactory->request<PhysicsComponent>()->request();// request<PhysicsComponent>() requests for the component manager instance, then request() is invoked from it which returns the component instance


Note that componentManagerFactory is not static. It's an instantiated class. I try to avoid singletons, too... and static.

I used boost::any to accomplish this.

This topic is closed to new replies.

Advertisement