alecthomas / entityx

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

Assigning Component in Update Loop Crashes #228

Closed sotrh closed 5 years ago

sotrh commented 5 years ago

I have a system that loops through all the entities with a Position component and checks if they are within a selection box. If they are in this box, the entity is assigned the Selection component.

void update(entityx::EntityManager &entities, entityx::EventManager &events, entityx::TimeDelta dt) {
    if (isSelecting) {
        renderer.render(selectionColor);
    }
    entities.each<Position>([this](entityx::Entity entity, Position& position) {
        auto pos = position.value;
        bool isSelected = false;

        if (pos.x > selection.minX 
            && pos.y > selection.minY 
            && pos.x < selection.maxX 
            && pos.y < selection.maxY) {
            entity.assign_from_copy<Selection>(selection);
            isSelected = true;
        }

        if (!isSelected && entity.has_component<Selection>()) {
            entity.remove<Selection>();
        }
    });
}

This code is crashing with Assertion!entity_componentmask[id.index()].test(family)' failed.`

Is there a way to do this in the loop, or do I have to collect a list of entities and assign the component in a second pass?

alecthomas commented 5 years ago

Try running the tests and following what they do. This definitely works.

alecthomas commented 5 years ago

Can you provide a minimal crashing sample?

sotrh commented 5 years ago

I figured out the problem. I was trying to add a component to an entity that already had one. Here's the working version.

void update(entityx::EntityManager &entities, entityx::EventManager &events, entityx::TimeDelta dt) {
    if (isSelecting) {
        renderer.render(selectionColor);
        entities.each<Position>([this](entityx::Entity entity, Position& position) {
            auto pos = position.value;
            bool isSelected = false;

            if (pos.x > selection.minX && pos.y > selection.minY && pos.x < selection.maxX && pos.y < selection.maxY) {
                if (!entity.has_component<Selection>()) {
                    entity.assign_from_copy<Selection>(selection);
                }
                isSelected = true;
            }

            if (!isSelected && entity.has_component<Selection>()) {
                entity.remove<Selection>();
            }
        });
    }
}

It would probably be a good idea to add some mention of the has_component to the component section.

Great library btw!