diff --git a/core/src/com/me/common/ecs/Engine.java b/core/src/com/me/common/ecs/Engine.java index a0b6c92..feb082a 100644 --- a/core/src/com/me/common/ecs/Engine.java +++ b/core/src/com/me/common/ecs/Engine.java @@ -66,24 +66,14 @@ public class Engine { return entityManager.create(); } - protected void activateEntity(Entity entity) { - entityManager.activate(entity); - } - - - protected void deactivateEntity(Entity entity) { - entityManager.deactivate(entity); - } - - - protected void removeEntity(Entity entity) { - entityManager.remove(entity); - } - public void callEvent(Event event) { listenerRegistry.callEvent(event); } + protected void refreshEntity(Entity entity) { + entityManager.queueRefresh(entity); + } + protected void removeAllEntityComponents(int entityId) { for (int i = 0; i < components.length; i++) { components[i].insert(entityId, null); diff --git a/core/src/com/me/common/ecs/Entity.java b/core/src/com/me/common/ecs/Entity.java index 808c8a6..4d06012 100644 --- a/core/src/com/me/common/ecs/Entity.java +++ b/core/src/com/me/common/ecs/Entity.java @@ -6,16 +6,19 @@ public final class Entity { private static long nextUniqueId = 0; private Engine engine; + protected final int id; - protected int id; protected long componentBits; + protected long systemEnabledBits; + + protected boolean active; + protected boolean removed; + protected boolean pendingRefresh; private long uniqueId; - private boolean active; protected Entity(Engine engine) { this.engine = engine; - this.active = false; this.id = nextId++; } @@ -33,16 +36,17 @@ public final class Entity { public void activate() { active = true; - engine.activateEntity(this); + refresh(); } public void deactivate() { active = false; - engine.deactivateEntity(this); + refresh(); } public void remove() { - engine.removeEntity(this); + removed = true; + refresh(); } public Engine getEngine() { @@ -59,10 +63,12 @@ public final class Entity { public void addComponent(Component component) { engine.addEntityComponent(this, component); + refresh(); } public void removeComponent(Component component) { engine.removeEntityComponent(this, component); + refresh(); } protected void addComponentType(ComponentType type) { @@ -73,9 +79,27 @@ public final class Entity { componentBits &= ~type.bits; } + protected void addSystemEnabledBit(long bit) { + systemEnabledBits |= bit; + } + + protected void removeSystemEnabledBit(long bit) { + systemEnabledBits &= ~bit; + } + + public void refresh() { + if (!pendingRefresh) { + engine.refreshEntity(this); + pendingRefresh = true; + } + } + protected void reset() { componentBits = 0; + systemEnabledBits = 0; active = false; + removed = false; + pendingRefresh = false; } protected void updateUniqueId() { diff --git a/core/src/com/me/common/ecs/EntityManager.java b/core/src/com/me/common/ecs/EntityManager.java index 9a6aa86..1528f45 100644 --- a/core/src/com/me/common/ecs/EntityManager.java +++ b/core/src/com/me/common/ecs/EntityManager.java @@ -7,114 +7,63 @@ final class EntityManager { private Engine engine; protected Array entities; - protected Array toActivate; - protected Array toDeactivate; - protected Array toRemove; protected Array removedEntities; + protected Array toRefresh; - public EntityManager(Engine engine) { + EntityManager(Engine engine) { this.engine = engine; - this.entities = new Array<>(); - this.toActivate = new Array<>(); - this.toDeactivate = new Array<>(); - this.toRemove = new Array<>(); + this.entities = new Array<>(false, 16); this.removedEntities = new Array<>(false, 16); - } - - public void update() { - activatePending(); - deactivatePending(); - removePending(); + this.toRefresh = new Array<>(false, 16); } public Entity create() { Entity entity; if (!removedEntities.isEmpty()) { entity = removedEntities.removeIndex(0); - entity.reset(); } else { entity = new Entity(engine); } + entity.reset(); entity.updateUniqueId(); entities.add(entity); return entity; } - public void remove(Entity entity) { - toRemove.add(entity); - } - - public void activate(Entity entity) { - toActivate.add(entity); - } - - public void deactivate(Entity entity) { - toDeactivate.add(entity); - } - - private void removePending() { - if (toRemove.isEmpty()) { + public void update() { + if (toRefresh.isEmpty()) { return; } - for (Entity entity : toRemove) { + for (Entity entity : toRefresh) { + refreshEntity(entity); + entity.pendingRefresh = false; + } + + toRefresh.clear(); + } + + public void queueRefresh(Entity entity) { + toRefresh.add(entity); + } + + private void refreshEntity(Entity entity) { + for (BaseSystem system : engine.systems) { + if (!(system instanceof EntitySystem)) { + continue; + } + + ((EntitySystem) system).refresh(entity); + } + + if (entity.removed) { engine.removeAllEntityComponents(entity.id); entities.removeValue(entity, true); - removeEntityFromSystems(entity); removedEntities.add(entity); } - - toRemove.clear(); } - private void activatePending() { - if (toActivate.isEmpty()) { - return; - } - - for (Entity entity : toActivate) { - addEntityToSystems(entity); - } - toActivate.clear(); - } - - private void deactivatePending() { - if (toDeactivate.isEmpty()) { - return; - } - - for (Entity entity : toDeactivate) { - removeEntityFromSystems(entity); - } - toDeactivate.clear(); - } - - private void removeEntityFromSystems(Entity entity) { - for (BaseSystem system : engine.systems) { - if (!(system instanceof EntitySystem)) { - continue; - } - - EntitySystem entitySystem = (EntitySystem) system; - if (entitySystem.interestedIn(entity)) { - entitySystem.removeEntity(entity); - } - } - } - - private void addEntityToSystems(Entity entity) { - for (BaseSystem system : engine.systems) { - if (!(system instanceof EntitySystem)) { - continue; - } - - EntitySystem entitySystem = (EntitySystem) system; - if (entitySystem.interestedIn(entity)) { - entitySystem.addEntity(entity); - } - } - } } diff --git a/core/src/com/me/common/ecs/EntitySystem.java b/core/src/com/me/common/ecs/EntitySystem.java index 378ee09..38ec1e6 100644 --- a/core/src/com/me/common/ecs/EntitySystem.java +++ b/core/src/com/me/common/ecs/EntitySystem.java @@ -2,14 +2,22 @@ package com.me.common.ecs; import com.badlogic.gdx.utils.Array; +import java.util.HashMap; +import java.util.Map; + public abstract class EntitySystem extends BaseSystem { + private static final Map, Long> systemBits = new HashMap<>(); + private static long nextBit = 1l; + + private long systemBit; private long typeBits; protected Array entities; public EntitySystem(Engine engine, Class... components) { super(engine); + this.systemBit = getBitFor(getClass()); this.typeBits = ComponentType.getMaskBits(components); this.entities = new Array<>(true, 16, Entity.class); } @@ -26,16 +34,36 @@ public abstract class EntitySystem extends BaseSystem { public abstract void processEntity(Entity entity, float dt); - public boolean interestedIn(Entity entity) { - return (entity.componentBits & typeBits) == typeBits; + protected void refresh(Entity entity) { + boolean enabled = (entity.systemEnabledBits & systemBit) == systemBit; + boolean interested = (entity.componentBits & typeBits) == typeBits; + + if (interested && !enabled && entity.active && !entity.removed) { + add(entity); + } else if (enabled && (!interested || !entity.active || entity.removed)) { + remove(entity); + } } - protected void addEntity(Entity entity) { + private void add(Entity entity) { + entity.addSystemEnabledBit(systemBit); entities.add(entity); } - protected void removeEntity(Entity entity) { + private void remove(Entity entity) { + entity.removeSystemEnabledBit(systemBit); entities.removeValue(entity, true); } + + static long getBitFor(Class es) { + Long bits = systemBits.get(es); + if (bits == null) { + bits = nextBit; + nextBit <<= 1; + systemBits.put(es, bits); + } + return bits; + } + }