xember
xember copied to clipboard
Multiple of same component in one entity?
I had a conversation via skype with a developer interested in component systems who asked me how I would handle the case where an entity needed to have multiple instances of a given component. His example was something like multiple mini-maps. I'm unconvinced about the use-case, and wondered whether anyone can think of a good use-case or has any thoughts about this?
In the asteroids example I use a gun component to represent the gun on the spaceship. I can imagine a situation where the spaceship has two guns, pointing in different directions. If xember doesn't handle multiple instances of the same component on one entity, I would solve this by creating the guns as separate entities, with a reference back to the spaceship entity that they're attached to. (Indeed that may be the best solution to this problem.) But being able to add two instances of the same component is a much easier solution for the developer.
Yeah, ok that makes sense. I think that this would be a significant feature.
In this case your entity has {Gun, Gun, GunControls, Position} so it'd need to be parsed into two nodes [{Gun A, GunControls, Position},{Gun B, GunControls, Position}]. Is this always the case? I'm just checking that I have the correct understanding of how the system should handle this sort of scenario before I go ahead and implement it!
Despite the example I gave, I'm not convinced this feature should be included. On the face of it, it looks simple. If an entity has two Gun components, and a family contains the Gun component and the GunControl component, then that entity should be in that family twice, once per instance of the Gun component.
But if the family contains the Gun component and the GunControl component, and an entity has two Gun components and two GinControl components, how many times should the entity be included in the family? It could be two, but then you have to know which GunControl goes with which Gun, or it could be four, to handle all combinations.
This is a can of worms that is best avoided.
The better solution in this instance is to create the gun as its own entity and give it a component that contains a reference to its parent, the spaceship entity, (or just its parent's Position component) so that it knows where it is in space. This solution also works for the first scenario and is possibly the correct solution all along.
Yeah, I see the problem. The combinatronics become extremely messy extremely quickly. There are lots of workarounds - everything could have a Guns component wtih a vector of Guns instead of one gun. In the mini-maps case, I'm sure it could be done with two minimap subtypes.
I've also started implementing this and found the amount of overhead is pretty concerning - you have to change quite a lot to get this functionality in, and maintainining an elegant system looks tough.
I want to copy in Ian, the guy who first brought up this situation for his response before I close the issue down, but for now I'll stop developing this feature.
Ok I have thrown together a quick example of a situation. I'm sure you could probably find alternative ways round it or say these should be seperate entities. But let's avoid that argument and let's say its set in stone that these components all 100% should be on the same entity because I can almost guarentee in a large game with more complex entities you will eventually hit this roadblock and be forced to refactor your core engine or split an entity even if you know it shouldnt be.
The situation: http://www.gliffy.com/publish/3010365/
The avatar system and the though bubble system are both dependent on the position component which is a shared component.
They are also dependent on a rendering component, however these must be different components containing different data.
They also both have their own individual component that contains specific data for the avatar and thought bubble systems.
I've been pondering the optimal solution for a while now and I have not come to any perfect solutions without any downfalls. Some possible solutions would be:
- Create them as seperate entities and provide an obscure reference to the position component for one entity. I think this would be a bad approach to take as you would be splitting up components that logically belong together.
- Create them as seperate entities with individual position components and somehow maintain both positions. This could potentially be a drain on resources with many unnecessary components to process.
- Extend/create a new rendering component for either the avatar node or though bubble node to force seperate dependancies. This would solve the issue quite easily but you would be in danger of creating an inheritance heavy system which is one of the things we are trying to avoid. It could however become an issue when for example if you needed 2 rendering components and 2 position components mapping on one entity,
- internal component mapping using strings. This would involve having an array of tags on components for dependencies. This is currently the solution im working on but its not perfect and not yet optimal for performance. It also handles situations where you might have for example 2 position and 2 rendering components or any number mapped out differently. This so far is quite costly as the components essentially have to be sorted into groups before node creation which would impact startup times or games creating alot of components on a regular basis. One thing worth a mention though is we could simply have a flag for components with multiple components (a data driven system could even automatically set the flag). If the flag is set do the more resource heavy dependency checking creation, if not dont bother just whack the entity into the nodes the same way as if you had a one component type per entity restriction. e.g positionComponent.internalMap=["Avatar","Thought"]; thoughtBubbleRenderer.internalMap=["Thought"]; avatarRenderer.internalMap=["Avatar"];
- SubSytems. This is a solution a friend at work came up with, the entity system its built though is different (PBE style) but I am pretty sure the concept would work for a system like xember. almost a sub entity/component on the entity with its own set of components which also uses child injectors to map dependencies from the parent entity. I cannot explain it fully as I have not gone through the code entirely so I don't want to explain anything incorrectly or make assumptions.
- Convince ourselves that this situation will probably never happen and if it does it must have been a design flaw. I think this would be naive and could realy limit the systems potential, we would be creating restrictions which could potentially be unnecessary.
I would love some more input and thoughts on this issue as I think it is potentially one of the biggest issues for entity/component systems and seems to be overlooked to often.
Hi Ian
Based on your diagram, you don't just need two RenderingComponents on your entity, you also need the entity manager to know the difference between them because you need one specific one inserted in the Avatar Node for the AvatarSystem to use, and you need another specific one inserted in the ThoughtBubbleNode for the ThoughtBubbleSystem to use.
Allowing multiple instances of a component on an entity can handle passing both components to the RenderingSystem, but it can't handle passing the correct component to each of these systems because, to the entity system, there is no difference between the two components - they are both instances of the same class.
I think you have two choices -
- Create a different component type for the ThoughtBubbleRenderingComponent (it may have the same set of properties as the RenderingComponent but it should be a different class) and have the RenderingSystem handle two sets of nodes, the RenderingNodes and the ThoughtBubbleRenderingNodes.
- Create the thought bubble as a separate entity. Give it a ThoughtBubbleComponent, and RenderingComponent, and the exact same PositionComponent as the PlayerEntity has (i.e. a reference to the same instance).
Neither of these requires the entity system to handle multiple entities of the same type.
I would favour the second solution. It keeps the RenderingSystem simple and it also scales to handle the case of the player having multiple thought bubbles.
In conclusion, I'd go for your option 6 until someone presents a scenario where multiple components is the best solution. I don't think your example does that.
You make a valid point but I think your missing my point, thats why I mentioned to ignore the flaws in the sample as they are not the point I am trying to focus on.
The issue would also exist in what you mention with if the player had multiple thought bubbles. Creating these as separate entity would bring almost the same issue as now you have to map either the full player entity to these new entities or individual components from the player entity. individual components sounds fine when it just needs the position but as it scales it could start to need more dependencies like the state of the player entity etc. It brings the issue that now you don't have to map the dependencies of the components confined within the entity but instead have to start mapping entity to entity dependencies on larger, more global scale. These components logically belong to the player entity and have clear dependencies on other components within the entity, but have an obvious need for clearly defined component to component relationships for node creation and system handling. I think you may me avoiding an issue that needs addressing and by offsetting the problem and trying to split an entity into multiple entities is going to bring about bigger issues and destroy the concept of entities simply being composed of components.
The first solution you mention would bring about unecessary inheritance or duplication of code, we shouldn't be simply creating new component classes every time we have a need for multiple components of the same type.
http://www.gliffy.com/publish/3012350/
I also just re-reading what you said and looking at the example, there wouldn't actually be an issue with the 2 renderers for the different system nodes as the mapping would be:
positionComponent.internalMap=["Avatar","Thought"]; thoughtBubbleRenderer.internalMap=["Thought"]; avatarRenderer.internalMap=["Avatar"]; avatarComponent.internalMap=["Avatar"]; thoughtBubbleComponent.internalMap=["Thought"];
which would create the groupings:
[thoughtBubbleComponent, thoughtBubbleRenderer, positionComponent] [avatarRenderer, avatarComponent, positionComponent] ["other non mapped components"]
This would create 2 nodes, one thoughtBubbleNode and one avatarBubbleNode and also two renderingNodes. Any other components outside the custom mapping would not be used together to create a node e.g. [thoughtBubbleRenderer, avatarComponent, positionComponent] would not be considered as they have different mappings.
If the player had multiple thought bubbles, then why can't you have a ThoughtBubblesComponent with Array<ThoughtBubble>? It means one extra loop per entity with a thought bubble, but at the benefit of simple architecture.
It's going to be difficult to argue your case in the abstract. If the example is not sufficient to require multiple components per entity, then we don't have a use-case.
I wasn't saying that your internal mapping solution wouldn't work, but that simply allowing multiple instances of a component, which is what this thread is about, wouldn't solve the problem. Further, I would contend that allowing multiple instances of a component on an entity does not help in any way to solving your problem, and adds lots of complexity to the core code.
If you look at the tags you're using for your internal map, you are separating your components into two sets - the thought bubble set and the player set. That can be handled equally well by using two entities.
I would agree that having a nice way to configure these complex entity dependencies and sharing of components would be good (although that needn't be part of the core engine, it could be a plug-in).
If we can agree that allowing multiple instances of a component is not the solution and has not been validated as a requirement, we can close this thread and start a new one to discuss how to make it easier to configure complex entity dependencies and sharing of components.
While it may not be validated as a requirement there is no existing solution so this should be an open issue at least until there is a concrete alternative in place.
Separating into various entities may solve the immediate issue of the multiple components of the same type but there would be no way to access shared components. You would then need managed entity-entity dependencies which has a much wider scope than the confined components of an entity and would likely be more complex code wise than local dependencies which is around 2 or 3 small function calls only executed on entities with multiple components with the same type. I would also argue that your not just simply going to be able to have these sort of dependencies contained on entities themselves as other approaches would as this would be going against the fundamental concepts of this type of entity system with entities containing only components with minimal data.
Also I am still working on the system and I'm still not 100% on the solution for the multiple component situation so it would be good if this could stay open so I can post some more proposed solutions or examples from my engine later on.
The shared components are components of both entities. They can be accessed from either component. They are the means of managing the entity-entity dependencies. Entities don't know about each other, just their own components. The entity itself needs no modification.
Hi guys, so I have been thinking a little more about whether there's a way to implement a solution to the problem that Ian perceives that is satisfactory.
I have to work from a concretish use-case, so here's what I was working on: The way I've framed it is that you have an entity with Position and Renderable components. Then, you add some sort of decorative renderable like a thought bubble. Let's call it Decoration, which extends Renderable. Ideally you'd like the Renderer System to catch both {Position, Renderable} and {Position, Decoration}.
I've also been working in my bitfield branch to make matching fast (I'm working around 32-bit limit), so I'm imagining the implementation it in these terms.
What if we allocate a bit to each component like this:
Position 0001 Renderable 0010 Decoration 0100
and maintain a separate mapping that 0100 extends 0010.
Then we define our Renderer:
Renderer from [Position, Renderable] 0011, 0101
We give it two patterns to match, because the inheritance mapping indicates that wherever there's a map 01X. there's also a map 10X.
So then
Entity [Position, Renderable] 0011 matches 0011 & 0011 == 0011 Entity [Position, Decoration] 0101 matches 0101 & 0101 == 0101
Entity [Position, Renderable, Decoration] 0111 matches 0111 & 0011 == 0011; also matches 0111 & 0101 == 0101
This seems elegant enough an implementation. The problem comes in where you might have some sort of super-position component, which adds a second position for collision detection, but isn't to be rendered
SuperPosition extends Position 1000 extends 0001
and we have a PhysicsSystem such that
Physics from [Position] 0001, 1000
but now Renderer from [Position, Renderable] matches 0011, 0101, 1010, 1100
and Entity Position, Renderable, Decoration, SuperPosition matches the Renderer 4 times.
This isn't what we want. So we need to be able to determine or the Renderer that yes, we want anything that matches both 0011 and 0101 but not 1010 or 1100. In simpler terms, we want to say use either Renderable or Decoration, but only use Position, not SuperPosition.
At the moment Nodes look like this:
public var RendererNode
{
...
[Ember(required)] public var position:Position;
[Ember(required)] public var renderable:Renderable
}
what about if
public var RendererNode
{
...
[Ember(required)] public var position:Position;
[Ember(required,subtypes)] public var renderable:Renderable
}
or
public var RendererNode
{
...
[Ember(required)] public var position:Position;
[Ember(required,accept="Decoration")] public var renderable:Renderable
}
or is there some other way? If there's a way to elegantly allow multiple matchers for a Nodes collection then it will be simple to implement. Any thoughts?
Hi All,
Im the colleague Ian was referring to when taking about the subsystem approach.
There definitely are times when its makes more sense to have multiple renderers on the same entity rather than making a new entity for the purpose.
Take the example of a 2D avatar in a game. The avatar has a spatial component and a renderer. Now suppose we want to add a shadow to the avatar. We dont want to bake it into the avatar graphic as we want it to change as the time of day progresses.
The way I tackled this in the second iteration of our entity-component system was to use a concept of 'subsystems'. A subsystem is basically just an entity. Infact EntitySubsystem extends EntityBase the same class that Entity extends from. So now I have my avatar class such as:
class Avatar extends Entity
{
public var spatial : SpatialComponent;
public var avatarRenderer : BlittingRenderingSubsystem;
public var shadowRenderer : BlittingRenderingSubsystem;
public var shadowController : ShadowControllerComponent;
override protected function onAddComponents() : void
{
spatial = addComponent(SpatialComponent);
avatarRenderer = addSubsystem(BlittingRenderingSubsystem);
shadowRenderer = addSubsystem(BlittingRenderingSubsystem);
shadowController = addComponent(ShadowControllerComponent);
}
}
Each entity in my system is given a child injector and each subsystem is given a child injector of that injector. This way the components in the subsystem can declare dependencies on each other and other components up the chain.
This also allows us to group together multiple components that always belong together. For example a BlittingRenderingSubsystem may have the following components to make it work: BlittingRenderingComponent, AssetLibraryModelComponent, AnimationSequenceComponent, AnimatorComponent, AnimatedFrameConfigModelComponent, EnviromentModifierComponent, BitmapPickableComponent.
The only problem is that a component at the entity level cant declare a dependency on a component inside the subsystem because it isnt available to the injector at that level. In this instance the dependency is manually provided:
protected function onPreComponentRegister() : void
{
shadowController.shadowRenderer = shadowRenderer.renderer;
}
I realise the system isnt perfect however the team seems to understand it and are developing some quite complex entities using it.
I am very interested to hear how xember will try to tackle this problem. I really like the look of that bit field approach alec, I would definitely like to hear more about that.
Mike
Mike
As you know, the architecture of your system is very different to Xember. In Xember, components are simple value objects, entites are just containers for components, and systems process collections of components. This simple clarity is what gives this architecture enormous scalability.
Most problems, including those presented here, can be solved perfectly well within these constraints. Among the tools that are often forgotten are
- a component may contain a collection of objects (e.g. the Rendering component may contain a vector of objects to render, containing both the avatar image and the shadow).
- a component may be owned by multiple entities. This provides the dependency between entities in a loosely coupled way.
It's my opinion that to add complexity to this because it feels like a more sensible way to solve a particular problem would be a mistake. (If we followed our OOP programmer instinct we'd end up with massive, convoluted inheritance trees of complex entities, which is precisely what Xember is designed to avoid). If a solution can't be found using these tools, then of course we have to consider adding complexity to the framework. But, so far, no problem has been presented that isn't readily solved with these tools.
So I say keep it simple.
By definition of components being data containers we cant simply have a list of something like separate renderables. While we could have a list of the actual objects to render we couldn't hold the rest of the required data for the separate renderable objects which would need more values, without having nested components. If we open it up to having nested components where already breaking a fundamental concept of the system.
Having a component owned by multiple entities is adding the complexity which you say you want to avoid. It could also be an issue in a data driven environment where you need to define component dependencies to multiple entities cleanly. This wouldn't be as big of an issue with component to component dependencies as it would be confined to a single entity rather than a global scale.
Ian
- Perhaps holding a collection of renderers in a component isn't the correct solution to the problem you express. I actually said in an earlier post that I think using separate entities is the correct solution. However, what I said above is that using components that contain collections is a tool that is often forgotten.
- No, allowing components to be owned by multiple entities doesn't add complexity to the system. Specifically, it requires no additions to the framework since this feature is inherent in the architecture of a component framework like Xember, and it should require no modifications to any systems in your game since systems should be agnostic to the origins of the components they handle.
There is, as I agreed above, an inherent complexity in configuring the entities and assigning them the correct components. That is not a side effect of sharing components between entities but is a reflection of the complexity of your game. As I also said, I think it would be worth kicking off a project to design a tool to help manage this configuration. It's worth bearing in mind that one of the reasons that Unity3d is so popular is the development tool they provide, and at its core this development tool is a tool for configuring entity systems.
I'm finding this conversation difficult because I have suggested what I consider the correct solution to your problem, to split your game character into multiple entities and share components between those entities as necessary. I believe this is right because it is how Xember is designed to work. It also requires no additions to Xember at all.
You have said that you don't like this, but the only reason you give is you think it will be hard to configure. An entity system like Xember pushes complexity out of the game and into the configuration. That is its nature. Your game has a certain level of complexity. You cannot hide from that, but you can decide how to handle it. If you don't want to handle it in the configuration then Xember is not the right tool for you.
Your comments on my proposed solution also suggest that you think there should be a one-to-one mapping between your game characters and your entities. This is a common mistake with an entity system like Xember. In Xember, entities are not game objects, they are simply a mechanism for grouping components, no more and no less. You should use them to group your components in the most practical way for your game. If that means treating a game character, its shadow and its thought bubble as three separate entities, then that is the correct way to do it.
Finally, you also say that your preferred solution is to put all the components on one entity and provide some sort of mapping to group the components. The problem with this, as you may realise from what I said in the previous paragraph, is that Xember already has a mechanism for grouping components. They're called entities. Xember doesn't need two mechanisms for this.
I do think that there is potential to allow a Node to specify an interface/base-class and match any implementing classes. Once I can roll out a bitfield implementation across current functionality, this can be done relatively pain-free. My main implementation concern for this has been the complexity of logic required to implement this, which would cause significant slow-down when a component is added or removed from a class. However, I think that the bitfield implementation gives an elegant mechanism that should be pretty quick. I will look to do some performance benchmarks once I've got a functional implementation.
On a more general note, I am really pleased that this conversation is happening. It is really useful to hear Mike and Ian's point of view, since it comes from more of a PushButtony architectural perspective. Amiable and constructive conversation for the win (I'm in the USA now, I have to use 'for the win' or similar once an hour). I broadly agree with Richard's point of view - that these issues 1. stem from a natural inclination to consider game objects single entities and 2. a reluctance to create complex 'configurators', instead hoping that the architecture will do the complex stuff for you 'under the hood'.
My yardstick is: if there is something that Xember can do that adds real power and doesn't add significant weight to the library, then I'm for it. Otherwise, I need to be convinced that the power-to-weight ratio is favourable. I'm only willing to consider the base properties implementation is that I think I understand a way to do it with very little added weight.
I did a quick-n-dirty Verlet physics engine in Ember, and was really unsure how to handle the individual points and sticks for each "entity". I wanted to use 3 points & sticks to create a "solid", and then render a bitmap at the "centre" of those 3 points. I ended up creating a "physics" component, which had slots for the 3 points and 3 sticks, but i wanted to "compose" multiple points and sticks. Wasn't sure how best to attain this, or if i was even going in the right direction.
The simplest solution if you want 2 guns: gunComponent.guns = 2
OR if gun position important: gunComponent.guns[0] = true // has 1st gun // has no 2nd gun by default gunComponent.guns[2] = true // has 3rd gun