Conversation started Jul 18, 2013 at 0:56.
Jul 18, 2013 00:56
Guys, i'm trying to understand component based systems. Does anyone know of any examples?
user4704
@user1895420 What don't you understand?
I don't think i've got a precise problem, which is why i'm looking for some example code :P
user4704
What do you expect to learn by just reading code though? It's extremely difficult to understand the "why" of most code, which means you often just end up copying things without a full understanding. Source code alone is a pretty poor learning medium.
user4704
You must have some idea why you are confused, though.
user4704
Otherwise you wouldn't know to ask for help.
Jul 18, 2013 00:59
haha that's true
i've been reading up on the ideas in this blog : t-machine.org/index.php/2007/09/03/…
user4704
Hrm.
But somewhere in there he sais something like: "entities should only store an identifier"
says*
user4704
That's not my favorite site.
not good?
Damn the internet and it's bad sources
user4704
You just need to treat it with a grain of salt like anything else.
user4704
Jul 18, 2013 01:01
So what's your confusion about storing an identifier?
Well he stresses that that's "all" an entity should store
user4704
That's one way to do it.
user4704
It's not the only way. The fundamental idea he's going for there (if I recall correctly) is valid.
So how then do i connect components to this entity?
user4704
It's the different between considering an entity to be: struct entity { std::vector<Component *> m_components; }
Jul 18, 2013 01:03
If it's not allowed to store any references to them
user4704
and struct entity { int id; }
user4704
And elsewhere, having a list of components associated with particular entities (conceptually: std::map<int, component *>, although that may not be the best specific implementation choice for a container)
user4704
The first approach (the list-of-components approach) is the naive one.
So why not just store the components in the entity?
user4704
Jul 18, 2013 01:04
It's quite functional however, and you can certainly make a system that way. It may be the better way to start out as it can be less confusing and less effort.
user4704
There are several reasons it is potentially bad, though.
user4704
The first is that it implies you do: foreach (entity in world) { foreach (component in entity) component.update(); } }, right?
Less confusing for sure :P
user4704
(well actually that's the main reason it's bad, but it leads to the other problems)
user4704
So what do you think might be a problem with that kind of update loop?
user4704
Jul 18, 2013 01:07
There are at least three big ones.
one sec, trying to write down my thoughts :P
I think i'm misunderstanding something, i thought components would only carry data. You would then select Entities with certain components and update them through some sort of System.
user4704
That's one way to do it.
oh god i'm going to make some sort of frankencode
user4704
It's not a wrong way, it's just different. You can consider components as data-only, and that tends to remove the explicit update method, but at some point that data usually gets updated.
But you learn so much from doing things that way :)
Jul 18, 2013 01:09
haha yea that's true
If you did things perfect the first time, you wouldnt learn much.
user4704
So there's still effectively the same process. You go through every entity, through all its components, and update them.
yea it seems so
user4704
Really, as an aside, there's something about component-based entity systems that seems to really mentally trip a lot of people up. There's no one true way to do it and you shouldn't worry about finding that one true way. You waste a lot of time that way. So I encourage you to experiment with various implementations and consider the pros and cons. You will learn much more that way.
user4704
That said, I'll tell you the potential issues with the first approach if you like.
Jul 18, 2013 01:12
I don't think there's ever one true way :P
please enlighten me :)
user4704
So, the first approach, at least that implementation, requires runtime dispatch of the update method (since you use polymorphism to store all the component pointers as pointers-to-base). Not huge, but it can add up.
user4704
A bigger issue, however, is that the components within an entity, and their ordering in the list, aren't defined.
user4704
That means you have very poor locality of reference in your code cache when you do that huge iteration.
What does that mean, locality of reference?
Stepping into the wonderful domain where data oriented and data oriented designs fight each other :P
user4704
Jul 18, 2013 01:15
@user1895420 Similar things stored next to eachother, essentially. Or similar things accessed in groups.
user4704
You basically update the components in any order. You might do "position, health, render, health, health, position, render, render," for example.
data oriented and object oriented designs*
user4704
Each time you jump to completely different locations in memory, which may not be in your cache, so you pay for a cache miss.
Ah i see, so that can slow down everything
user4704
Locality of reference is the reason that arrays are almost always better than linked lists.
user4704
Jul 18, 2013 01:17
Even for iterating across every element in the list, which appears to be algorithmically similar in complexity.
user4704
So, the biggest issue, which is related to the last one, is that there is no sane way to federate that update loop across multiple threads without knowing a lot about the data dependencies of each component relative to all other components in the system.
user4704
So, it can be very difficult to efficiently distribute the processing of all components over all your available cores.
user4704
That's where the alternative approach of making an entity "just" an ID comes into play.
user4704
This is also known as an "outboard" approach: gamedev.net/topic/…
How does that take away the problem then?
user4704
Jul 18, 2013 01:20
Essentially, you have various interfaces (often called "systems" but they need not be all inherited from some ISystem interface, per se) that create and own the individual components.
user4704
So you might have a system for physics, say PhysicsWorld. And a system for rendering, say Visualizer.
user4704
The actual entity system exposes hooks to allow you to connect callbacks for when entities are created or destroyed.
user4704
So, when you say entitySystem->CreateEntity(), the entity system creates a new entity object, assigns it an ID, and raises an event saying "Entity 32 was just created!"
user4704
(and similarly when an entity is deleted).
user4704
Any interested systems can inspect the entity ID -- and probably in practice the entity data file that describes what components should be in the entity -- and decide if it needs to create a corresponding component.
user4704
Jul 18, 2013 01:22
So, the physics system might create a RigidBody and associate it with entity ID 32.
user4704
The visualizer might create a sprite and associate it with entity 32.
user4704
But maybe the audio system says "I don't need to deal with entity 32 since his data description doesn't say he has an audio component."
user4704
And so it does nothing.
I see, so the components are stored at the systems, no at the entities.
user4704
Yup.
user4704
Jul 18, 2013 01:24
And you can Update() the entity system, which goes through all its components and updates them, if needed.
user4704
This way, every component in the system can be interacted with via its concrete type, and no virtual function calls are required. You update a lot of the same components with one call (and those components are probably stored next to eachother) for improved locality of reference.
user4704
And you know there are no concrete physical dependencies between systems, since the components have no direct access to eachother and don't even neccessarily know they are "components" in the sense of being inherited from IComponent.
user4704
That means you can update physics and rendering on two different threads, potentially
user4704
(although in practice, physics and rendering do often have a logical dependency that means you'd want to serialize their update, but other things don't)
So what if a system uses two different components? Or needs a component created by another system?
Or should that not be possible
user4704
Jul 18, 2013 01:27
A system can create as many different types of "components" as it needs for a given entity.
user4704
If the visualizer needs to create both a 2D sprite and a 3D model for a thing, it can. It can store and manage those as best suites the needs and performance of the system.
So what if one system creates a 'physicsComponent' and another system wants to use it?
user4704
If you need access to other types of components from other systems, you need to fabricate a means of establishing that dependency.
user4704
That's one of the potential disadvantages of this approach (although I would argue it's still mostly an advantage, because it forces you to be very explicitly about which types of systems can communicate with other systems)
Dang, it gets complicated quite quickly.
user4704
Jul 18, 2013 01:30
It's not that bad. Don't confuse explicitness with complexity.
user4704
Implicit is often more complex in practice than the other way around.
user4704
The simplest way to establish that kind of communication is to synchronize the domain of the entity ID between all systems. In other words, make sure that any system that must expose its components via its public API has a way to look up a component by some ID that always happens to be the entity ID.
user4704
So, if the visualizer needs to recover the position information from the physics system so it can draw a sprite, it can do something like:
user4704
body * b = physicsWorld->get_rigid_body(sprite->entityId);
user4704
To do this, of course, your visualizer must have access to the physics system, so you'd want to something like: Visualizer(PhysicsWorld * physicsWorld) as the constructor of your visualizer.
Jul 18, 2013 01:33
Allright, so then the communication is explicit.
user4704
(personally I prefer to avoid that specific dependency since it means I can't draw things without physics and I don't always want them; I keep physics and render position distinct, and have a higher-level system -- usually the 'game' class itself -- manage the synchronization, effectively)
user4704
but that is neither here nor there
Thanks very much for the explanation btw.
user4704
np
I hadn't realised there were so many different ways of doing it tbh
user4704
Jul 18, 2013 01:37
There's a lot more than that, too, depending on how particular you want to get.
user4704
But the major division is "components in entity," or "components in system."
user4704
After that its just flavor
 
Conversation ended Jul 18, 2013 at 1:38.