I’m having a little trouble with EntityX and Box2D - particularly with assigning a fixture’s userData to an Entity.
Here’s the code I have when I create a new entity that has a Body/Fixture:
Entity myEntity = _entities.create();
myEntity.assign<Body>( pos ); //assign a component to the entity
//set up fixture etc
b2FixtureDef * fixtureDef = new b2FixtureDef();
b2CircleShape * circle = new b2CircleShape();
circle->m_radius = 0.15f;
fixtureDef->shape = circle;
//here I tell the fixture to point to the 'owner' entity
fixtureDef->userData = &myEntity;
The issue is that, when I later use
Entity * entityA = static_cast<Entity*>(contact->GetFixtureA()->GetUserData());
inside my Contact Listener, the resulting entity pointer counts an ‘invalid’ entity - so I cant do anything with it - EntityX will just crash if I try and check for components, or check it’s id.
As far as I can tell, it’s because the initial “myEntity” object is a temporary object - so I’m actually assigning a pointer to a useless temporary object. I can’t think of anyway to get around this, however. “entities.create()” is just the way that EntityX creates entities.
Any ideas how I can get around this? It’s possible I’m just approaching this the wrong way entirely!
Entity have a copy constructor? If so (and it looks like it), you could try this:
Entity *myEntity = new Entity( _entities.create() );
You may have to call
myEntity->invalidate() to disassociate it from the
EntityManager, as explained here.
Note that I have never used EntityX myself, I only just heard about it.
I haven’t used
EntityX either, so I might be quite wrong about this. But from what I understand, the
Entity object is very thin, just capturing the
id of a particular object. Instead of storing a pointer to the
Entity object, you might be better off storing the id as the
userData in the Box2D object. Or even better, store the information regarding the
contact in a
Component in your
Entity. Then your
System can query the bunch of entities based on this particular
Let us know how your experiment goes!
Thanks for the help guys - I think I (finally) got somewhere with this.
I tried a whole bunch of approaches, but I think the flaw in the system is that Box2D requires a pointer to an object for a fixture’s
userData, and EntityX doesn’t seem to have particularly concrete data structure. I couldn’t assign entities or entity IDs, as they both counted as temporary objects. I could assign a pointer to a component - but once it came to accessing the entity at the point of collision, the components
.entity() method would point to a null (invalid) entity.
So instead, I added a new a uint64_t field to b2Body which could store the owner entity’s ID itself. Then I could just look up the entity via ID at the point of collision, and send events out from there.
Box2D does not touch
userData at all. Its use and interpretation is completely upto us.
I was under the impression that you could extract the entitys
uint64_t through something like
id().id(). But on the whole, your solution seems to be what I had in my mind. Thank you for updating us!
That’s what I tried! Unfortunately if I try
fixture.userData = &entity.id().id();
I get the error
cannot take the address of an rvalue of type 'uint64_t'
fixture.userData = new uint64_t(entity.id().id());
does work. I wonder if this is a better option? Or could this result in memory leaks?
Thats because you are trying to use the address of a value ( not a variable ).
Originally, I was thought you could store the value itself in
userData, not a pointer. But now I realize that it is possible only if you are using a 64 bit build, since the id is of type
uint64_t. For a 32 bit build, size of
void * would be 32 bits, and a
uint64_t would not fit in there.
While you could create a pointer to a
uint64_t and store it in
userData, you would have to delete it yourself, or you will leak memory. But this doesn’t sound like the ECS way of doing things. You might be better off sticking the id ( the
uint64_t value ) in a collision
Component which you can process from your
System. Please check out the example here.