Hi folks,
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!
Does 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.
-Paul
Hi,
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 Component
.
Let us know how your experiment goes!
Bala.
2 Likes
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 id
as 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'
However…
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.
Bala.
1 Like