From f366c4b80839a4be29770fe6d1715163d482c5be Mon Sep 17 00:00:00 2001 From: Matt Low Date: Mon, 27 Jan 2020 03:10:42 +0400 Subject: [PATCH] Simply entity refreshing. Consolidate toRemove, toEnable toDisable into toRefresh, move logic of whether an entity should be added or removed to an EntitySystem into EntitySystem. Entities now have a systemBits member which represents which systems they're currently a part of and is used by the refresh() logic in EntitySystem. Adding or removing components from an entity after it has been created and activated will now add or remote the entity from relevant systems. --- core/src/com/me/common/ecs/Engine.java | 18 +-- core/src/com/me/common/ecs/Entity.java | 36 +++++- core/src/com/me/common/ecs/EntityManager.java | 109 +++++------------- core/src/com/me/common/ecs/EntitySystem.java | 36 +++++- 4 files changed, 95 insertions(+), 104 deletions(-) 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; + } + }