Box2D Joints in entity components system
- by Johnmph
I search a way to have Box2D joints in an entity component system, here is what i found :
1) Having the joints in Box2D/Body component as parameters, we have a joint array with an ID by joint and having in the other body component the same joint ID, like in this example :
Entity1
- Box2D/Body component { Body => (body parameters), Joints => { Joint1 => (joint parameters), others joints... } } // Joint ID = Joint1
Entity2
- Box2D/Body component { Body => (body parameters), Joints => { Joint1 => (joint parameters), others joints... } } // Same joint ID than in Entity1
There are 3 problems with this solution :
The first problem is the implementation of this solution, we must manage the joints ID to create joints and to know between which bodies they are connected.
The second problem is the parameters of joint, where are they got ? on the Entity1 or Entity2 ? If they are the same parameters for the joint, there is no problem but if they are differents ?
The third problem is that we can't limit number of bodies to 2 by joint (which is mandatory), a joint can only link 2 bodies, in this solution, nothing prevents to create more than 2 entities with for each a body component with the same joint ID, in this case, how we know the 2 bodies to joint and what to do with others bodies ?
2) Same solution than the first solution but by having entities ID instead of Joint ID, like in this example :
Entity1
- Box2D/Body component { Body => (body parameters), Joints => { Entity2 => (joint parameters), others joints... } }
Entity2
- Box2D/Body component { Body => (body parameters), Joints => { Entity1 => (joint parameters), others joints... } }
With this solution, we fix the first problem of the first solution but we have always the two others problems.
3) Having a Box2D/Joint component which is inserted in the entities which contains the bodies to joint (we share the same joint component between entities with bodies to joint), like in this example :
Entity1
- Box2D/Body component { Body => (body parameters) }
- Box2D/Joint component { Joint => (Joint parameters) } // Shared, same as in Entity2
Entity2
- Box2D/Body component { Body => (body parameters) }
- Box2D/Joint component { Joint => (joint parameters) } // Shared, same as in Entity1
There are 2 problems with this solution :
The first problem is the same problem than in solution 1 and 2 : We can't limit number of bodies to 2 by joint (which is mandatory), a joint can only link 2 bodies, in this solution, nothing prevents to create more than 2 entities with for each a body component and the shared joint component, in this case, how we know the 2 bodies to joint and what to do with others bodies ?
The second problem is that we can have only one joint by body because entity components system allows to have only one component of same type in an entity.
So we can't put two Joint components in the same entity.
4) Having a Box2D/Joint component which is inserted in the entity which contains the first body component to joint and which has an entity ID parameter (this entity contains the second body to joint), like in this example :
Entity1
- Box2D/Body component { Body => (body parameters) }
- Box2D/Joint component { Entity2 => (Joint parameters) } // Entity2 is the entity ID which contains the other body to joint, the first body being in this entity
Entity2
- Box2D/Body component { Body => (body parameters) }
There are exactly the same problems that in the third solution, the only difference is that we can have two differents joints by entity instead of one (by putting one joint component in an entity and another joint component in another entity, each joint referencing to the other entity).
5) Having a Box2D/Joint component which take in parameter the two entities ID which contains the bodies to joint, this component can be inserted in any entity, like in this example :
Entity1
- Box2D/Body component { Body => (body parameters) }
Entity2
- Box2D/Body component { Body => (body parameters) }
Entity3
- Box2D/Joint component { Joint => (Body1 => Entity1, Body2 => Entity2, others parameters of joint) } // Entity1 is the ID of the entity which have the first body to joint and Entity2 is the ID of the entity which have the second body to joint (This component can be in any entity, that doesn't matter)
With this solution, we fix the problem of the body limitation by joint, we can only have two bodies per joint, which is correct.
And we are not limited by number of joints per body, because we can create an another Box2D/Joint component, referencing to Entity1 and Entity2 and put this component in a new entity.
The problem of this solution is : What happens if we change the Body1 or Body2 parameter of Joint component at runtime ? We need to add code to sync the Body1/Body2 parameters changes with the real joint object.
6) Same as solution 3 but in a better way : Having a Box2D/Joint component Box2D/Joint which is inserted in the entities which contains the bodies to joint, we share the same joint component between these entities BUT the difference is that we create a new entity to link the body component with the joint component, like in this example :
Entity1
- Box2D/Body component { Body => (body parameters) } // Shared, same as in Entity3
Entity2
- Box2D/Body component { Body => (body parameters) } // Shared, same as in Entity4
Entity3
- Box2D/Body component { Body => (body parameters) } // Shared, same as in Entity1
- Box2D/Joint component { Joint => (joint parameters) } // Shared, same as in Entity4
Entity4
- Box2D/Body component { Body => (body parameters) } // Shared, same as in Entity2
- Box2D/Joint component { Joint => (joint parameters) } // Shared, same as in Entity3
With this solution, we fix the second problem of the solution 3, because we can create an Entity5 which will have the shared body component of Entity1 and an another joint component so we are no longer limited in the joint number per body.
But the first problem of solution 3 remains, because we can't limit the number of entities which have the shared joint component.
To resolve this problem, we can add a way to limit the number of share of a component, so for the Joint component, we limit the number of share to 2, because we can only joint 2 bodies per joint.
This solution would be perfect because there is no need to add code to sync changes like in the solution 5 because we are notified by the entity components system when components / entities are added to/removed from the system.
But there is a conception problem : How to know easily and quickly between which bodies the joint operates ?
Because, there is no way to find easily an entity with a component instance.
My question is : Which solution is the best ? Is there any other better solutions ?
Sorry for the long text and my bad english.