alecthomas / entityx

EntityX - A fast, type-safe C++ Entity-Component system
MIT License
2.22k stars 295 forks source link

Question: recommendation for passing entity to function. #165

Closed visorz closed 7 years ago

visorz commented 7 years ago

I am wondering what is the best way to pass an entity to a function. First I wanted to just pass a reference to the variable in the entity component e.g:

auto& pointRef = &( camera.component<Position>().get()->point );

This is not possible, because point is a temporary variable. I guess because it is the object referenced by a shared_ptr. That is why I now pass the Entity::Id and lookup the Position component in the function itself.

void functionMgr( const entityx::Entity::Id cameraID, entityx::EntityManager& entities ) 
{
    auto camera =   entities.get( cameraID );    
    if ( camera.component<Position>().get() )
        camera.component<Position>().get()->point = newPosition;
}    

For this I have to pass the EntityManager, too. To reduce the function parameters to one I could pass only the Entitiy itself:

void functionE( entityx::Entity camera )
{
   if ( camera.component<Position>().get() ) 
        camera.component<Position>().get()->point = glm::vec3( 1 );
}

Or better because less data, only the address of it:

void functionPtr( entityx::Entity& camera )
{
   if ( camera.component<Position>().get() ) 
        camera.component<Position>().get()->point = glm::vec3( 1 );
}

sizeof( entityx::Entity::Id );  // 8 byte
sizeof( entityx::Entity );      // 16 byte
sizeof( entityx::Entity* );     // 8 byte

But is this the way I am supposed to do it? And what is you recommendation for the valid() test? Should I always check an entity before accessing its components by using if ( myEntity.get() ) { ... } ?

And should I check a component before access with

entity.component<Position>().get()

or with

entity.component<Position>().valid()
alecthomas commented 7 years ago

What version are you using? The current version does not use shared_ptr<> at all.

Using pos = entity.component<Position>() will return a ComponentHandle<Position> which is a kind of smart pointer. You can check its validity before use with if (pos.valid()).

Entity itself should only be sizeof(uint64_t) + sizeof(EntityManager*) in size, and is designed to be copied around and used. As with ComponentHandle you can check the validity of an Entity with entity.valid().

As to when you should check validity, that is up to you. Entity and ComponentHandle are both handles, and if you keep copies of them around you need to be aware of whether the underlying entity or component can be destroyed.

I would rewrite your function like so:

void functionMgr( const entityx::Entity camera ) 
{
  auto position = camera.component<Position>();
  if ( position )
    position->point = newPosition;
}   
visorz commented 7 years ago

Thank you for the clarification, I will use your recommended way of passing entities. I am using version 1.1.2.