   Thoughts on this component system for a game engine.
  I have been working on my new game engine that will be based around the component based entity system. I would like to know what everyone thinks of this system for implementing the components.The Components only store data and the engine Systems contain functionality.The Engine class contains a static Component Manager class that acts as a database with the components being stored in a vector. The Component Manager has functions like GetComponentsByEntity that takes a input of a string entity name and loops through all of the components, fills a output vector with any Components who's EntityName variable is the same as the input, and returns the output vector. There are three other functions: GetComponentsByType, GetComponentByName, and GetComponentByTypeAndEntity.As an example of usage the Render System has an octree that is created at start. Every time the Scene changes(Scene is just a part of the engine state manager of game states), the Render System get's all of the objects that need to be rendered by calling GetComponentsByType("Renderable"). Then every frame(or possibly only when receiving an update message) the Render System determines where the Renderables are located in the octree by iterating over all of the Renderables and calling GetComponentByTypeAndEntity("Positionable", renderables->GetEntity()) and using the output to place the Renderables vector id into the BranchNode of the octree.There will be a fixed set of Component Types that will be able to be used. Game logic will be done in Script Components that load up a lua script.I would appreciate and comments, suggestions, and constructive criticism that anyone has to offer.Thanks. :)
  sounds hideously slow and complicatedstring compares? in your render loop? come  on  man!if you want to have as single list of items, and have those items mean different things, perhaps you should look at a spanning array. although you have to iterate through a list of objects to update them, you may as well check if you can render them at that point in time.sounds like your trying to go the DOM sort of direction, where you have a cloud of  stuff  and filter it based on what you want to do. sure it  sounds  like a good idea, but really, it tends to be a hideous mess of untyped crap. and ive seen engines try it (even commercial ones). keep it simple.. keep it explicit.. dont try to hide complexity behind even more complexity.   ;  I had a feeling that this implementation was not the greatest way to manage this. :(  I am still not the most experienced of coders and sortof just wanted to start planning how i wanted the engine to be used and then ask more experienced coders for advice on how to optimize it. :PThanks for the advice about spanning arrays. I will look into that. But everyone please keep the ideas coming. :)Thanks   ;Quote:Original post by Matt_Dsounds hideously slow and complicatedstring compares? in your render loop? come  on  man!The above concept can be implement as 'return renderables;', so this "hideously slow" is a single pointer assignment.In general, the problem of GetComponentByType can be implement in a completely trivial manner - each component registers with its relevant system. So Renderable puts itself into Renderable list. And so on.Even more, components can be allocated inside this list, which means that they can be traversed very efficiently.The biggest bottleneck comes from ad-hoc queries and arbitrary lookups, where you are constrained to whatever indexing scheme is used. These will be some function of n, and frequently impacted by cache misses. Fortunately, these will be limited to logic, which is rarely a bottleneck, even if implemented completely in scripting language.   ;  I have been thinking about other possible solutions and i have a couple questions. I am now starting to think about possibly just having a Map of the for each type of component inside of the Systems rather than a single vector of components.For an example i will go back to the Render System. The Render System has a member variable of a std::map<std::string entityName, Renderable component>;. Whenever the user of the engine calls Engine::AddRenderable(renderableDesc);, the Engine just has the Render System add a new Renderable with the members passed by the renderableDesc. The same thing happens with the Movement System and the Movable components. Then whenever the Render System needs to get the position it just requests it straight from the Movement System with a call to Engine::GetMovable(std::string entity);, which just fetches the Movable from the MovementSystem Map by using the entity key.Here are my questions: #1. Does this sound like a good plan? #2. It seems as if the best way to implement this would be with static functions for the Add???() and Get???() functions. Would there be any problem with doing that for a dll Game Engine?Thanks again for the help.   ;  I use the component system and love it. It helps keep all the logic separate, so a game object will have a base entity component, a basebrain component and a Base Physics component (physics, graphics, AI, etc). If you make an abstract interface you can easily change the entire portions of the engine without any trouble at all (IE I can easily change from Havok to physX or whatever without much bother).   ;  Ahh, "component system."  Sounds awfully complicated.struct PositionComponent {    float x, y, z;};struct RenderComponent {    PositionComponent &pos;  // a required subcomponent};struct Entity {    PositionComponent pos; // a member subcomponent    RenderComponent *r; // an optional subcomponent};Then you could maintain a list of RenderComponents to draw each frame, or a list of Entities to go through each frame and do things for each component.Dunno why everyone always goes and makes this all complicated with ids and names and stuff.  What's wrong with pointers/references/members at this level? EDIT: Unless you're trying to do this across threads.   ;  What if not all entities have RenderComponents? You've wasted a pointer. What if you have lots and lots of component types? You've wasted lots and lots of pointers. What if you want an entity to have multiple components of the same type? Make it an array? What if you want to add and remove these dynamically? Tough bits.It's easy to say "look, it can be this simple!" if your problem is also very simple, but games aren't that simple.   ;Quote:If you make an abstract interface you can easily change the entire portions of the engine without any trouble at all (IE I can easily change from Havok to physX or whatever without much bother).I plan for my engine to be able to do this by having the Systems be separate from the wrapper. As an example with my plan for physics: the Physics System isn't a wrapper around anything, instead it is just what runs the simulation. Slightly separated from the Physics System are the interfaces like PhysicsScene and PhysicsJoint. Those interfaces are the wrappers around the api functionality and the Physics System just manages them. Kinda hard to explain.   ;Quote:Original post by hymermanWhat if not all entities have RenderComponents? You've wasted a pointer. What if you have lots and lots of component types? You've wasted lots and lots of pointers. What if you want an entity to have multiple components of the same type? Make it an array? What if you want to add and remove these dynamically? Tough bits.It's easy to say "look, it can be this simple!" if your problem is also very simple, but games aren't that simple.Dare I say: "Who cares?"I'll waste a million pointers if it means that I don't have to spend an extra hour poking around through a tangled mess of ((ThingieComponent)entity->;GetComponent[COMPONENT_ID_THINGIE])->;DoSomethingToAnotherEntity(somethingElse);...class ThingyComponent : Component {    void DosomethingToAnotherEntity(Entity& entity) {   ((PositionComponent)entity.GetComponent[COMPONENT_ID_POSITION]).Translate(1, 2, 3);    }}Games are complicated. Why further complicate them with complexities that aren't necessary. Go ahead and waste a meg (or shall I say 'mib?') of RAM on unneeded pointers. Maybe you'll force the user to upgrade? [We don't need off-handed political and/or racially coloured comments in here, thanks - Zahlman][Sorry! Wasn't thinking. Patrick][Edited by - smr on June 2, 2009 9:37:20 PM]