Changed array types, increasing performance

This commit is contained in:
Brychan Dempsey 2021-06-11 20:55:05 +12:00
parent 529f99abbd
commit 999ffa41dd
3 changed files with 36 additions and 17 deletions

View File

@ -16,18 +16,22 @@ package nz.ac.massey.javaecs;
import java.util.Map; import java.util.Map;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
class ComponentArray{ class ComponentArray{
// The object data array // The object data array
private List<Object> componentArray = new ArrayList<>(); private List<Object> componentArray;
// The mappings between data and entity // The mappings between data and entity
private Map<Entity, Integer> entityComponentDataMap = new HashMap<>(); private Map<Entity, Integer> entityComponentDataMap;
private Map<Integer, Entity> componentDataEntityMap = new HashMap<>(); private Map<Integer, Entity> componentDataEntityMap;
public ComponentArray(int initialSize){
componentArray = new ArrayList<>(initialSize);
entityComponentDataMap = new HashMap<>(initialSize);
componentDataEntityMap = new HashMap<>(initialSize);
}
/** /**
* Gets the data Object associated with the entity. * Gets the data Object associated with the entity.
* @param entity the entity to find data for * @param entity the entity to find data for

View File

@ -121,11 +121,21 @@ class ComponentManager{
* @return true if the component was registered successfully, else false * @return true if the component was registered successfully, else false
*/ */
protected boolean registerComponent(Type type){ protected boolean registerComponent(Type type){
return registerComponent(type, 16);
}
/**
* Registers the component type
* @param type the class type to register
* @param arraySize the number of elements to prereserve space for.
* @return true if the component was registered successfully, else false
*/
protected boolean registerComponent(Type type, int arraySize){
if (componentArrays.containsKey(type)){ if (componentArrays.containsKey(type)){
Engine.writeErr("Component " + type.getTypeName() + " is already registered"); Engine.writeErr("Component " + type.getTypeName() + " is already registered");
return false; return false;
} }
componentArrays.put(type, new ComponentArray()); componentArrays.put(type, new ComponentArray(arraySize));
indexComponentType.put(componentPosIndex.size(), type); indexComponentType.put(componentPosIndex.size(), type);
componentPosIndex.put(type, componentPosIndex.size()); componentPosIndex.put(type, componentPosIndex.size());
return true; return true;

View File

@ -9,10 +9,10 @@ package nz.ac.massey.javaecs;
*/ */
import java.util.BitSet; import java.util.BitSet;
import java.util.LinkedList; import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Queue; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
// Define the manager classes internally - should be moved to seperate source files as appropriate // Define the manager classes internally - should be moved to seperate source files as appropriate
@ -22,7 +22,11 @@ import java.util.ArrayList;
* I.e. Controls adding and removing entities, and registration and deregistration of components. * I.e. Controls adding and removing entities, and registration and deregistration of components.
*/ */
class EntityManager{ class EntityManager{
private Queue<Entity> unusedEntities; // According to https://stackoverflow.com/questions/12524826/why-should-i-use-deque-over-stack
// ArrayDeque is likely faster than a LinkedList, when used as one.
// We can also supply a size to the constructor of ArrayDeque, which avoids resizing the collection
// at initialisation time (took 1.4s vs 1.8s for 1M)
private Deque<Entity> unusedEntities;
private List<BitSet> entityRegistrations; private List<BitSet> entityRegistrations;
private int maxSize = 1024; private int maxSize = 1024;
@ -30,8 +34,8 @@ class EntityManager{
* Initialise the EntityManager with the default max size of 1024 * Initialise the EntityManager with the default max size of 1024
*/ */
public EntityManager(){ public EntityManager(){
unusedEntities = new LinkedList<>(); unusedEntities = new ArrayDeque<>(maxSize);
entityRegistrations = new ArrayList<>(); entityRegistrations = new ArrayList<>(maxSize); // Init to maxSize to increase performance
for (int i = 0; i < maxSize; i++) { for (int i = 0; i < maxSize; i++) {
unusedEntities.add(new Entity(i)); unusedEntities.add(new Entity(i));
@ -45,8 +49,8 @@ class EntityManager{
*/ */
public EntityManager(int maxEntities){ public EntityManager(int maxEntities){
maxSize = maxEntities; maxSize = maxEntities;
unusedEntities = new LinkedList<>(); unusedEntities = new ArrayDeque<>(maxSize);
entityRegistrations = new ArrayList<>(); entityRegistrations = new ArrayList<>(maxEntities);
for (int i = 0; i < maxEntities; i++) { for (int i = 0; i < maxEntities; i++) {
unusedEntities.add(new Entity(i)); unusedEntities.add(new Entity(i));
@ -180,7 +184,7 @@ class EntityManager{
// Consistency should be maintained. // Consistency should be maintained.
// This is computationally expensive; we must re-order every assigned entity above newSize, if the newSize is smaller // This is computationally expensive; we must re-order every assigned entity above newSize, if the newSize is smaller
if (newSize < maxSize){ if (newSize < maxSize){
List<Entity> outOfBounds = new ArrayList<>(); Deque<Entity> outOfBounds = new ArrayDeque<>(maxSize - newSize);
for (int i = newSize; i < maxSize; i++) { for (int i = newSize; i < maxSize; i++) {
Entity entityI = Entity.asEntity(i); Entity entityI = Entity.asEntity(i);
if (!unusedEntities.remove(entityI)){ if (!unusedEntities.remove(entityI)){
@ -189,14 +193,15 @@ class EntityManager{
outOfBounds.add(entityI); outOfBounds.add(entityI);
} }
} }
for (Entity integer : outOfBounds) { while(outOfBounds.size() > 0){
Entity old = outOfBounds.remove();
Entity newPos = addEntity(); Entity newPos = addEntity();
setRegistrations(newPos, getRegistrations(integer)); setRegistrations(newPos, getRegistrations(old));
// Invoke an update in the SystemManager // Invoke an update in the SystemManager
systemManager.entityDestroyed(integer); systemManager.entityDestroyed(old);
systemManager.entityRegistrationsChanged(newPos, getRegistrations(newPos)); systemManager.entityRegistrationsChanged(newPos, getRegistrations(newPos));
// Invoke the change in the components // Invoke the change in the components
componentManager.moveAllComponentData(integer, newPos, getRegistrations(integer)); componentManager.moveAllComponentData(old, newPos, getRegistrations(old));
} }
for (int i = newSize; i < maxSize; i++) { for (int i = newSize; i < maxSize; i++) {
// Remove out-of-bounds data // Remove out-of-bounds data