diff --git a/javaecs/src/main/java/nz/ac/massey/programming_project_159333_s1_2021/ECS.java b/javaecs/src/main/java/nz/ac/massey/programming_project_159333_s1_2021/ECS.java index b63f839..1cee030 100644 --- a/javaecs/src/main/java/nz/ac/massey/programming_project_159333_s1_2021/ECS.java +++ b/javaecs/src/main/java/nz/ac/massey/programming_project_159333_s1_2021/ECS.java @@ -32,7 +32,71 @@ public class ECS { // Unfortunately, given Java's constraints on dynamic typing (run-time type determination), the returned data must be // explicitly cast. Therefore, all components must implement the IComponent interface - which mandates the getType() // function - List> componentDataArrays = new ArrayList<>(); + + // As discussed by Austin Morlan, this array must be packed, otherwise we waste time iterating over non-subscribed entities + // This also means we cannot use the location implicitly - we must keep track of exactly which data instance associates with + // which entity. + // Therefore, we need a custom data structure that keeps reversable references to component instances and entities: + interface IComponentArray{ + void entityDestroyed(int entity); + } + class ComponentArray implements IComponentArray{ + List componentArray = new ArrayList<>(); + Map entityComponentDataMap = new HashMap<>(); + Map componentDataEntityMap = new HashMap<>(); + + public void entityDestroyed(int entity){ + Optional pos = entityComponentDataMap.get(entity); + if (pos.isEmpty()){ + removeData(entity); + } + } + + void removeData(int entity){ + if (!entityComponentDataMap.containsKey(entity)){ + System.err.println("Attempted to remove non-existent entity"); + return; + } + // Get the componentData index of the entity + int removedComponentDataIndex = entityComponentDataMap.get(entity); + // Replace the removed component with the last component in the array + componentArray.set(removedComponentDataIndex, componentArray.get(componentArray.size() -1)); + // update the data positions in the map + int lastEntity = componentDataEntityMap.get(componentArray.size()-1); + entityComponentDataMap.replace(lastEntity, removedComponentDataIndex); + componentDataEntityMap.replace(removedComponentDataIndex, lastEntity); + // Finally, remomve the last elements + entityComponentDataMap.remove(entity); + componentDataEntityMap.remove(componentArray.size() -1); + + componentArray.remove(componentArray.size() -1); + } + + void insertData(int entity, E component){ + Optional pos = entityComponentDataMap.get(entity); + if (!pos.isEmpty()){ + System.err.println("Entity is already subscribed to the component"); + return; + } + int index = componentArray.size(); + entityComponentDataMap.put(entity, index); + componentDataEntityMap.put(index, entity); + + componentArray.add(component); + } + + E getData(int entity){ + if (!entityComponentDataMap.containsKey(entity)){ + System.err.println("Attempted to retrieve non-existent data"); + return null; + } + + return componentArray.get(entityComponentDataMap.get(entity)); + } + } + // The actual list of data arrays + List componentDataArrays = new ArrayList<>(); + // Components are either primitive types or class/struct definitions, with an additional list associating // the entities the component is assigned to