Jump to content

  • Log In with Google      Sign In   
  • Create Account


Component Based Entity System Question


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 CRYP7IK   Members   -  Reputation: 885

Like
0Likes
Like

Posted 14 September 2011 - 06:37 AM

Hey all, I would like your opinion on something...Okay so:

Say you have a component based entity system and your system is kind of normal:

Where an Entity is a ComponentContainer and an AttributeContainer.

Components are things that use attributes (The entity holds the attributes so that two components can say...access the Mesh attribute or health...) and can add\get attributes to an Entity.

Attributes are pretty obvious.

Now lets say you have your Renderable3D component, and when it gets added to an Entity or created you need it to also get added to the Renderer so it can be rendered...

How would you do this? Make the Renderer a singleton? (OnEntityAdded or Initialise on the component could then just add itself...)

Or have a GameSystem that would hold a Renderer* and was a singleton?

Or...? A solution without singletons!?
To accomplish great things we must first dream, then visualize, then plan...believe... act! - Alfred A. Montapert
Gold Coast Studio Manager, Lead Programmer and IT Admin at Valhalla Studios Bifrost.

Sponsor:

#2 arbitus   Members   -  Reputation: 436

Like
1Likes
Like

Posted 14 September 2011 - 07:13 AM

Why not construct the Renderer with a list of Renderables, inject the entity container into the Renderer so that it can request a list of renderables, subscribe the renderer to the entity system so that it listens for when a Renderable3D is attached, or any of a million other scenarios that don't involve singletons?

#3 SiS-Shadowman   Members   -  Reputation: 359

Like
1Likes
Like

Posted 14 September 2011 - 07:25 AM

My system is pretty similar to yours, but instead of the entities holding the attributes, components do. When another component requires the same attribute, it must say so when it's attached to the entity (via requirements). Anyways, I have a big entity system that consists of subsystems. Each subsystem handles ONE specific type of a component. The one system holds all renderables, the other one all collidables, and so forth. This way I can render all renderables "at once" (the subsystem obviously holds an entity => component dictionary) and do collision tests for all components in the other subsystem.

So basically you add one system per component (sometimes I do need a small hierarchy in components, so I've restricted my rule to having one subsystem per DIRECT subclass of component: all further subclasses are put into the same system). If you're interested, I can send you my sources.



#4 speciesUnknown   Members   -  Reputation: 527

Like
2Likes
Like

Posted 14 September 2011 - 07:43 AM

Hey all, I would like your opinion on something...Okay so:

Say you have a component based entity system and your system is kind of normal:

Where an Entity is a ComponentContainer and an AttributeContainer.

Components are things that use attributes (The entity holds the attributes so that two components can say...access the Mesh attribute or health...) and can add\get attributes to an Entity.

Attributes are pretty obvious.

Now lets say you have your Renderable3D component, and when it gets added to an Entity or created you need it to also get added to the Renderer so it can be rendered...

How would you do this? Make the Renderer a singleton? (OnEntityAdded or Initialise on the component could then just add itself...)

Or have a GameSystem that would hold a Renderer* and was a singleton?

Or...? A solution without singletons!?


I cheat. I have a method call on my entity class, which it delegates to all its components: void populateRenderList(MainRenderList list)

This way, on each frame, anything within the frustum is asked to add anything it wishes to the render list. This is highly useful for components which aren't normally drawn, but which I might want to draw something for debugging purposes.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!

#5 Hodgman   Moderators   -  Reputation: 29552

Like
2Likes
Like

Posted 14 September 2011 - 07:46 AM

Now lets say you have your Renderable3D component, and when it gets added to an Entity or created you need it to also get added to the Renderer so it can be rendered...
How would you do this? Make the Renderer a singleton? (OnEntityAdded or Initialise on the component could then just add itself...)
Or have a GameSystem that would hold a Renderer* and was a singleton?
Or...? A solution without singletons!?

Singletons are almost never the right solution, especially in high-level code like this.

The easiest way (IMO) to enforce this restriction ("when it is created you need it to also get added to the Renderer") is to require the renderer be passed to the constructor. In order to create a Renderable3D component, you need to have a reference to the Renderer (which you should be able to pass around without resorting to global variables...)
class Renderable3D
{
public:
  Renderable3D( Renderer& r ) : parent(r) { parent.Add( this ); }
  ~Renderable3D() { parent.Remove( this ); }

  static void AddToEntity( Entity& e, Renderer& r )
  {
    e.AddComponent( new Renderable3D(r) );
  }
private:
  Renderer& parent;
  Renderable3D();
  Renderable3D( const Renderable3D& );
};

However, I'd prefer a simpler design that only has components and systems -- no attributes or even entities -- the game code can create it's own entities however it likes by grouping together component handles however it likes (probably with entities being programmed in another language like Lua, rather than in C++)
class RendererSystem
{
public:
  int CreateRenderable()
  {//some simple handle-based allocation, e.g.
    int id = components.size();
    components.resize( id + 1 );
    return id;
  }
private:
  std::vector<Renderable3D> components;
};

struct MyRenderableEntity
{
  MyRenderableEntity( RendererSystem& r ) : myRenderable(r.CreateRenderable()) {}
  int myRenderable;
}


#6 latent   Members   -  Reputation: 139

Like
1Likes
Like

Posted 14 September 2011 - 08:10 AM

How would you do this? Make the Renderer a singleton? (OnEntityAdded or Initialise on the component could then just add itself...)

Or have a GameSystem that would hold a Renderer* and was a singleton?

Or...? A solution without singletons!?


I've just been putting a first-attempt at an entity system into my wip over the last couple of days. It's probably got issues, and I've combined my attributes and component concept into one - but I've gone for a solution that allows me to do something like this:

[source lang="cpp"]//Render all the ModelC componentsModelC::RenderAll(); //ModelC maintains all instances of its type and this function calls Render() for_each//Add a ModelC to entity via one of several methodsentity->AddComponent(CID_MODEL);//orModelC *model = ModelC::Create(entity); //the object is added to ModelC; we can safely let the newComponent pointer fall out of scope//Access a ModelC for entityModelC *model = ModelC::Get(entity);[/source]

The implementation relies on each component class simply having a static std::vector containing pointers to all instances of its type. So... yeah it requires static data, but not singletons, per se.

#7 CRYP7IK   Members   -  Reputation: 885

Like
0Likes
Like

Posted 14 September 2011 - 08:37 AM

Why not construct the Renderer with a list of Renderables, inject the entity container into the Renderer so that it can request a list of renderables, subscribe the renderer to the entity system so that it listens for when a Renderable3D is attached, or any of a million other scenarios that don't involve singletons?


Those are all great ideas, however I still don't see how the user of my system will easily create an Entity that is able to be Rendered. Easy as in, oh I just give it a 3DRenderable component with a file name to a mesh and it is now being rendered at it's position! (Preferably they will also just be defining this entity in an XML file, or even further in an editor). I am leaning towards your third proposed idea, however that way the entity system will need to know about the Renderer so it can add a 3DRenderable if an entity is added with one attached to it...Yes?

If I was going to force them to get a Renderer pointer and give it to the 3DRenderable, how would I let them get that pointer?

Wow those are a lot of responses with a lot of good discussion material and they are making me re-think my current system! I will have to read and respond to them all later as it's 12:36 AM here in Brisbane and I have a meeting at 9:35 AM!

Thanks all! Posted Image
To accomplish great things we must first dream, then visualize, then plan...believe... act! - Alfred A. Montapert
Gold Coast Studio Manager, Lead Programmer and IT Admin at Valhalla Studios Bifrost.

#8 Nanoha   Members   -  Reputation: 296

Like
1Likes
Like

Posted 14 September 2011 - 09:30 AM

Each of my components have a component loader (simple factory), my entity factory has all these "loader" objects. The graphical one does whatever it need to (loading models, attaching things and what not) - it knows how to add things to the scene and so on. The component doesn't need to know these things (at some point it might). I can define my entities using xml like:

<Entity>
   <Components>
      <Graphical>
         <SceneNode>
            <Mesh>
            </Mesh>
         </SceneNode>
      </Graphics>
   </Components>
</Entity>

The entity factory checks if it can load a given component type, if it can - then it goes ahead uses its sub factory to do so. As I'm using factories, once the entity factory is initially created, I do longer need to pass around anything like the scene/physics and so the factory can be used pretty much anywhere without problem.

My Graphical component just holds a "SceneNode" pointer, thats enough to do what I need with it (move the visuals mainly).

#9 VReality   Members   -  Reputation: 436

Like
1Likes
Like

Posted 14 September 2011 - 05:52 PM

...
Lets say you have your Renderable3D component, and when it gets added to an Entity or created you need it to also get added to the Renderer so it can be rendered...

How would you do this?
...


The rendering system should own the renderables, and the entities should get references to them them from the rendering system.

This takes care of the registering-renderables-with-the-renderer issue. But it also allows the rendering system to manage the memory of the data it works with, so that it can process in a somewhat cache coherent way.


...the entity system will need to know about the Renderer so it can add a 3DRenderable if an entity is added with one attached to it...Yes?


Yeah, the components may handle all interaction with their respective systems, but at some level whatever code decides it needs one of those components to add to an entity will need access to those systems to either get the components or register them. Depending on how things work, this code may not actually live in the entity system.

#10 CRYP7IK   Members   -  Reputation: 885

Like
0Likes
Like

Posted 14 September 2011 - 07:16 PM

My system is pretty similar to yours, but instead of the entities holding the attributes, components do. When another component requires the same attribute, it must say so when it's attached to the entity (via requirements). Anyways, I have a big entity system that consists of subsystems. Each subsystem handles ONE specific type of a component. The one system holds all renderables, the other one all collidables, and so forth. This way I can render all renderables "at once" (the subsystem obviously holds an entity => component dictionary) and do collision tests for all components in the other subsystem.

So basically you add one system per component (sometimes I do need a small hierarchy in components, so I've restricted my rule to having one subsystem per DIRECT subclass of component: all further subclasses are put into the same system). If you're interested, I can send you my sources.


It is not completely obvious to me why a sub-system holds a dictionary of entity -> component (I assume by component, it is the actual component the sub-system deals with) that may be because:

A. My components can keep references to attributes that the entity has. (If you need position from the entity in the dictionary)
B. My components have a reference to the entity that contains it.

Do your components not know about their entities?

I cheat. I have a method call on my entity class, which it delegates to all its components: void populateRenderList(MainRenderList list)

This way, on each frame, anything within the frustum is asked to add anything it wishes to the render list. This is highly useful for components which aren't normally drawn, but which I might want to draw something for debugging purposes.


So the list gets given to the Renderer...how?

For example, lets say I was coding away in my GameState and I wanted to create an entity that is just a box that can be knocked around with physics:
(This is my current way, that I want to change from using singletons.)

Entity* myEntity = new Entity(); 
myEntity->AddComponent(new Renderable3D("box.mesh", true, Position));
myEntity->AddComponent(new PhysicsObject3D(meshBoundsShape, Weight));


Now in those three constructors they each add themselves to each system, the Entity gets an ID from the GameSystem (Via singleton) and puts itself into the GameSystem the same way. The Renderable3D does the same with it's RenderSystem and same with the PhysicsObject3D...This makes it easy for a user of my system to create entities because things auto-magically go into their systems.

Singletons are almost never the right solution, especially in high-level code like this.



Yeah, that's what I am trying to fix. My thinking that singletons fix everything!



The easiest way (IMO) to enforce this restriction ("when it is created you need it to also get added to the Renderer") is to require the renderer be passed to the constructor. In order to create a Renderable3D component, you need to have a reference to the Renderer (which you should be able to pass around without resorting to global variables...)


That's great and all, but then how does the user of this system access the renderer, do I have to force them to create it themselves in whatever state they want to render in?

Using your first example, contrasting to my above one:

Entity myEntity;
AddRenderable3DToEntity(myEntity, rendererThatIDontHaveHowDoIGetIt);


would you then have to go:

Renderer* renderer = new Renderer(stuff);

Entity myEntity;
AddRenderable3DToEntity(myEntity, *renderer );
ChangeState("game", New GameState(), renderer); // Change state and pass in Renderer...

I feel that is bad, because my user then has to worry about keeping his renderer available, which he may then just might make a global variable anyway...

However, I'd prefer a simpler design that only has components and systems -- no attributes or even entities -- the game code can create it's own entities however it likes by grouping together component handles however it likes (probably with entities being programmed in another language like Lua, rather than in C++)

class RendererSystem
{
public:
  int CreateRenderable()
  {//some simple handle-based allocation, e.g.
    int id = components.size();
    components.resize( id + 1 );
    return id;
  }
private:
  std::vector<Renderable3D> components;
};

struct MyRenderableEntity
{
  MyRenderableEntity( RendererSystem& r ) : myRenderable(r.CreateRenderable()) {}
  int myRenderable;
}


I kind of like this idea, but then how does the RenderSystem get to the game code where you are creating that entity? This is how I originally started doing this kind of system, however I didn't know how to make it data-driven and easily make it able to be scripted.

Man I am so confused now...
To accomplish great things we must first dream, then visualize, then plan...believe... act! - Alfred A. Montapert
Gold Coast Studio Manager, Lead Programmer and IT Admin at Valhalla Studios Bifrost.

#11 Hodgman   Moderators   -  Reputation: 29552

Like
1Likes
Like

Posted 14 September 2011 - 07:45 PM

Here's a very simple set-up that passes a renderer-pointer to the factory that is creating entities:[source lang=cpp]struct GameEngine{ Renderer* renderer; OtherSystem* blah;};class EntityFactory{ GameEngine& engine;public: EntityFactory( GameEngine& e ) : engine(e) {} Entity* LoadSomething(const std::string& file) { Renderer* r = engine.renderer; .... }};class Game{ EntityFactory factory;public: Game( GameEngine& e ) : factory(e) {}};int main(char** argc, int argv){ GameEngine engine = CreateEngine(argc, argv); Game game( engine ); while(1) { game.Update(); game.Render(); }}[/source]

#12 CRYP7IK   Members   -  Reputation: 885

Like
0Likes
Like

Posted 14 September 2011 - 10:12 PM

Here's a very simple set-up that passes a renderer-pointer to the factory that is creating entities:


Okay, I kind of see now...would it also be a good idea to allow someone to add entity types to the EntityFactory so that they could request that type again and get all the components added to it that the user specified?

And with this method, I will need a factory...for pretty much every system correct? Sound \ Physics \ Event \ Message \ Network \ State?
To accomplish great things we must first dream, then visualize, then plan...believe... act! - Alfred A. Montapert
Gold Coast Studio Manager, Lead Programmer and IT Admin at Valhalla Studios Bifrost.

#13 SiS-Shadowman   Members   -  Reputation: 359

Like
1Likes
Like

Posted 14 September 2011 - 11:21 PM


My system is pretty similar to yours, but instead of the entities holding the attributes, components do. When another component requires the same attribute, it must say so when it's attached to the entity (via requirements). Anyways, I have a big entity system that consists of subsystems. Each subsystem handles ONE specific type of a component. The one system holds all renderables, the other one all collidables, and so forth. This way I can render all renderables "at once" (the subsystem obviously holds an entity => component dictionary) and do collision tests for all components in the other subsystem.

So basically you add one system per component (sometimes I do need a small hierarchy in components, so I've restricted my rule to having one subsystem per DIRECT subclass of component: all further subclasses are put into the same system). If you're interested, I can send you my sources.


It is not completely obvious to me why a sub-system holds a dictionary of entity -> component (I assume by component, it is the actual component the sub-system deals with) that may be because:

A. My components can keep references to attributes that the entity has. (If you need position from the entity in the dictionary)
B. My components have a reference to the entity that contains it.

Do your components not know about their entities?

Yes, in fact they do. This is because my entities don't have a list of components attached to them, instead the subsystems take care of that. I figured that I'll propbably never need to get ALL components of an entity, only a subset.


When creating an entity, it only references the entitysystem it has been created with. Upon adding a component, for examble your Renderable3D, the entity defers the call to the entity system, which in fact defers the call to the right sub-system. It will in return add the (entity, renderable) pair into it's dictionary.

Entity e = entitySystem.CreateEntity();
e.Add(alreadyExistingRenderable3DComponent);

I solved the attribute problem by allowing components to reference other components, in fact, each component type specifies a Template that describes what this component actually requires. For example a renderable would require a transformable (everything that can be rendered must have a translation). This requirement now changes the process a bit. Upon adding the Renderable component, the entitysystem verifies that ALL requirements are met and if they are, the component is added. Otherwise an exception is thrown, containing all requirements that are not met. (The same procedure is done upon removing a component).


Entity e1 = entitySystem.CreateEntity();

e1.Add(new Transformable());

e1.Add(new Renderable3D());

Entity e2 = entitySystem.CreateEntity();

e2.Add(new Renderable3D()); //< throws because the transformable component is missing


That very same template can be used to construct a component (because it is in fact a string => object dictionary + a list of required components) through a subsystem. My subsystems are not only responsible for calling update / draw on their components, the also serve as factories to create a component from a certain template. On top of that I have a template collection that describes an entire entity. This way I can create a template for a starship, store that template somewhere and finally create a thousand starships, only passing that template to the entity system.

var template = new EntityTemplate();
dynamic transformable = ComponentTemplate.FromType<Transformable>();
transformable.Position = new Point(10, 100, -15);
transformable.Orientation = new Quaternion(....);
dynamic renderable = ComponentTemplate.FromType<Renderable>();
renderable.Mesh = "bunny.x";
renderable.Material = "bla"
template.Add(transformable);
template.Add(renderable);

Entity entity = entitySystem.CreateEntity(template);
// Entity now contains 2 components (transformable and renderable)

// Both components will have all properties extracted from the template upon construction



FYI: I'm using IronPython to describe all my components & entities, so I can simply redefine them while the game is running (and hence my c# example using the "dreaded" dynamic).

*edit* I forgot to mention that when retrieving a specific component from an entity, you specify it's type. The entity simply delegates the call to the entity system which in turn delegates it to the subsystem, responsible for that type (this method is mostly used upon entity creation and when components are attached):



Transformable t = e.Component<Transformable>();

Renderable3D r = e.Component<Renderable3D>();


*edit2* So to sum it up, the ENTIRE state is kept in the entity system. All a user has to do is to have a reference to it. The entity system takes care of registering the components with the right sub-system. This way you don't need global access to the renderer because the right sub-system has access to it (because it was given the renderer during construction), no need for global access to the physics simulator because of the very same reason.







Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS