1
\$\begingroup\$

I'm designing a simple Arcanoid game with ECS.

With ECS there are many systems that only update components once in a while. For example, Particle systems are animated sprites that can be used for collision effects or explosions. These kind of effects happen rarely.

ParticleSystem will only update ParticleComponent when they exist, which happens rarely, just on collisions, etc. The rest of the time it's polling to find entities with ParticleComponent.

Isn't this polling inefficient? If I have many more functions similar to the ParticleSystem, that only do work rarely, the update will be clogged with systems that do not update anything. Would it be good practice to "sleep" the system until an entity is assigned to the ParticleComponent?

For example (using EntityX):

class ParticleComponent : Component<ParticleComponent>
{
public:
    ParticleComponent(ParticleId id) : id(id), time(0.0){};

    ParticleId id;
    double time;
};

class ParticleSystem : System<ParticleSystem>
{
public:
    void update(EntityManager & entities, EventManager & events, TimeDelta dt)
    {
        // this list will be empty if there are no entities.. but there is still a search
        entities.each<ParticleComponent>([](Entity & entity, ParticleComponent & particle)
        {
            // update current animation time
            particle.time += dt;
        });
    }
};

class Game : public EntityX
{
public:
    Game()
    {
        systems.add<ParticleSystem>();
        systems.configure();
    }

    void update(TimeDelta dt)
    {
        // this is only useful when there are entities with ParticleComponents
        systems.update<ParticleSystem>(dt); 
    }

    void onRareEvent()
    {
        auto entity = entities.create();
        entity.assign<PositionComponent>();
        entity.assign<ParticleComponent>(FIRE_PARTICLE);
        // destroy in 3 seconds
        timer.schedule(3, Game::destroyEntity, entity);
    }

    //void render()...    
}
\$\endgroup\$

migrated from stackoverflow.com Mar 10 '17 at 10:04

This question came from our site for professional and enthusiast programmers.

2
\$\begingroup\$

ParticleSystem will only update ParticleComponent when they exist, which happens rarely, just on collisions, etc. The rest of the time it's polling to find entities with ParticleComponent.

Isn't this polling inefficient?

No, it's not efficient, but there's no reason to do it that way and no (good) ECS implementation will poll for components.

When a component/entity is created, add the component/entity to the systems's list of active objects if the object meets the appropriate requirements (some systems require a combination of components, sometimes called a "component signature" by hip youthful people). Then the system consistently has an accurate list of all objects it needs to update and the information it needs to access them efficiently, no polling required.

This is true in an ECS architecture or other component architectures. Our engine is a very far cry from ECS and yet we do the same thing: components call something like game.SomeManager.addComponent(this) in their initialization function and game.SomeManager.removeComponent(this) in their shutdown function. Fancier ECS architectures automate that, but it's the same idea.

I would have assumed that libraries like EntityX are actually doing this under the hood, but I could be wrong. Every single off-the-shelf open source entity library I've ever seen on GitHub (EntityX included) is hot flaming garbage and I'd recommend that you run screaming in the opposite direction, anyway. If you think you need a complex library to manage your game objects, that's a sign that you're massively over-complicating the problem. And if you're using some crazy template meta-programming nonsense (like EntityX) you're potentially shooting yourself in the foot (that stuff will have trouble scaling past the smallest and simplest hobby games, especially if you at all value the time lost waiting for your game to compile).

\$\endgroup\$
  • 1
    \$\begingroup\$ If each system has its own list of entities with X-Component, what would happen with all-famous PositionComponent? All systems that require position must have a list with the entities with PositionComponent? \$\endgroup\$ – Hennio Mar 14 '17 at 8:17
  • 1
    \$\begingroup\$ @Hennio: something like that. A good implementation will just have a single list per system of all entities that have the required components. e.g., your PhysicsSystem would have a list of entities with both body and transform/position components. It doesn't need separate lists of each. That single system's list entries might contain pointers for each entity to its components or just rely on having O(1) access to components via the entity's identifier. Something like struct MySystemEntry { Entity id; Body* body; Transform* transform; }; vector<MySystemEntry > _entities; \$\endgroup\$ – Sean Middleditch Mar 14 '17 at 17:08
  • \$\begingroup\$ @SeanMiddleditch: Not relevant to the question, but out of curiosity --- what exactly makes every single open-source entity library "hot flaming garbage"? Do you have any specific complaints (apart from overcomplicating matters, but that is specific to EntityX)? \$\endgroup\$ – Tim Čas Jul 17 '17 at 13:33
  • \$\begingroup\$ @TimČas: every off-the-shelf entity library I've seen so far both over-complicates parts that don't need it (e.g., using compile-time meta-programming for things that could/should be data-driven) as well as leaving out all the hard bits of integration necessary to build a real game/engine/toolkit (diagnostic tools, dependency/editor metadata, etc.). using an off-the-shelf library gives you a few hundred lines of code handling only the easiest parts of a component model but typically in a way that ties ones hands down the road. it's a lose-lose. \$\endgroup\$ – Sean Middleditch Jul 17 '17 at 19:18
  • 1
    \$\begingroup\$ @rickyviking: Few possible solutions. A layer of indirection like a "slot_map" (youtube.com/watch?v=SHaAR7XPtNU) is pretty common for these purposes. A second typical approach is to notify systems upon entity/component removal about the reordering. \$\endgroup\$ – Sean Middleditch Sep 19 '17 at 23:22
0
\$\begingroup\$

Particles is something that doesn't fit inside a component.

Instead you want spawning particles as a possible behavior of the collision component.

Then the particles themselves are in a flat array that you can loop over and update positions and render them all easily.

class ParticleSystem{

    std::vector<Particle> particles;

    public:
    void spawn(...); //push_back some new particles based on args

    void update(TimeDelta dt){

        for(auto it = particles.begin(); it != particles.end();++it){
            do{
            it->ttl -= dt;
            if(it->ttl < 0) {
                //particle died, remove from list;
                swap(it*, particles.back());
                particles.pop_back();
                if(it == particles.end())return;
            }
            while(it->ttl < 0);

            //update pos and vel of it*
            it->pos+=it->val * dt;
            it->vel+=it->accel*dt;
        }

    }

}

Particle system can always update and will usually have some particles to move but the spawn is only called from other components based on certain triggers.

This changes from poll notification to push notifications. Which if things are idle most of the time is much better for performance.

\$\endgroup\$
  • \$\begingroup\$ Are you refering to particle simulation? I refer to Particle systems as in animated sprites for sparks/dust/explosion effects. The component would define which effect it wants to render and the current animation time. The question refers to the efficiency of having a system idling waiting to update the component when it happens (very rarely) \$\endgroup\$ – Hennio Mar 12 '17 at 20:45
  • \$\begingroup\$ @MartinMatilla particles after being created don't need to be tied to the originator. So it's better for the collision system to be the push trigger. So when it's "idling" it's not taking up any CPU. \$\endgroup\$ – ratchet freak Mar 12 '17 at 23:26
  • \$\begingroup\$ What is idling is the particle system that updates(delta dt) the current time of the particle component. It is using cycles to check if there is any particle component to update. I just want to note that Particle System when talking about ECS is the system that updates Particle Components.. maybe there is being a misunderstanding with Particle System as an animated sprite \$\endgroup\$ – Hennio Mar 13 '17 at 8:14
  • \$\begingroup\$ I differentiate between the particle itself (the animated sprite) and the system that spawns them in response to events in the world. The sprite itself will need an update but a single Particles entity that stores all currently alive particles will be able to handle that. \$\endgroup\$ – ratchet freak Mar 13 '17 at 9:27
  • \$\begingroup\$ @MartinMatilla if nothing happens in update(delta) then it doesn't need to be a component that has a update(delta). Instead it can be an observer that just gets notified by other components when certain events happen. \$\endgroup\$ – ratchet freak Mar 13 '17 at 9:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.