com.artemis.managers.ComponentManager Maven / Gradle / Ivy
package com.artemis.managers;
import com.artemis.Component;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.utils.SafeArray;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Bits;
import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.badlogic.gdx.utils.Pools;
/**
* Responsible for pooling and managing of Components and their
* mapping to entities.
*/
public class ComponentManager extends Manager {
protected Array> componentsByType;
protected Array deletedEntities;
protected ObjectMap componentsToDelete;
protected ObjectMap, ComponentMapper>> mappers;
protected static int nextComponentClassIndex = 0;
protected static ObjectIntMap> componentClassIndeces =
new ObjectIntMap>();
Array returnedComponents;
/**
* Returns the index of a Component class. Indices are cached, so retrieval
* should be fast.
*
* @param type Component class to retrieve the index for.
* @return Index of a specific component class.
*/
public static int getComponentClassIndex(Class extends Component> type) {
if (componentClassIndeces.containsKey(type)) {
return componentClassIndeces.get(type, -1);
} else {
componentClassIndeces.put(type, nextComponentClassIndex);
return nextComponentClassIndex++;
}
}
/**
* Default constructor
*/
public ComponentManager() {
componentsByType = new SafeArray>();
deletedEntities = new Array();
componentsToDelete = new ObjectMap();
this.mappers = new ObjectMap, ComponentMapper>>();
this.returnedComponents = new Array();
}
/**
* Preferred way to create Components to allow for pooling.
*
* @param Type of component
* @param type Type of component to create
* @return Pooled Component of specified type.
*/
public T createComponent(Class type) {
return Pools.obtain(type);
}
/**
* Clean up Components belonging to the Entity
* @param e Entity to clear components for.
*/
public void removeComponentsOfEntity(Entity e) {
Bits componentBits = e.getComponentBits();
for (int i = componentBits.nextSetBit(0); i >= 0; i = componentBits.nextSetBit(i+1)) {
removeComponent(e.id, i);
}
componentBits.clear();
}
/**
* Adds a Component bellonging to the specified Entity to the manager.
*
* @param Type of component
* @param e Entity the component belongs to
* @param component Component to add
*/
public void addComponent(Entity e, T component) {
int classIndex = getComponentClassIndex(component.getClass());
@SuppressWarnings("unchecked")
Array components = (Array) componentsByType.get(classIndex);
if(components == null) {
components = new SafeArray();
componentsByType.set(classIndex, components);
}
// clean up existing component belonging to the entity
Component current = components.get(e.id);
if (current != null && current != component) {
Pools.free(current);
}
components.set(e.id, component);
e.getComponentBits().set(classIndex);
}
/**
* Remove Component of specified class for a given Entity.
*
* @param e Entity to remove the component for.
* @param type Component class to remove.
*/
public void removeComponent(Entity e, Class extends Component> type) {
int classIndex = getComponentClassIndex(type);
if(e.getComponentBits().get(classIndex)) {
e.getComponentBits().clear(classIndex);
if (!componentsToDelete.containsKey(e)) {
componentsToDelete.put(e, Pools.obtain(IntArray.class));
}
componentsToDelete.get(e).add(classIndex);
}
}
/**
* Returns an Array of all Components of specified type.
*
* @param Type of component
* @param type Type of Componets to return
* @return an Array of said components.
*/
@SuppressWarnings("unchecked")
public Array getComponents(Class type) {
int classIndex = getComponentClassIndex(type);
Array components = (Array) componentsByType.get(classIndex);
if(components == null) {
components = new SafeArray();
componentsByType.set(classIndex, components);
}
return components;
}
/**
* Returns Component of the specified type belonging to specified Entity.
* Null if not found.
*
* @param Type of component
* @param e Entity to return Component for.
* @param type Type of Component to return.
* @return Component or null if not found.
*/
@SuppressWarnings("unchecked")
public T getComponent(Entity e, Class type) {
int classIndex = getComponentClassIndex(type);
Array components = (Array) componentsByType.get(classIndex);
if(components != null) {
return components.get(e.id);
}
return null;
}
/**
* Fills an array with Components belonging to the specified Entity.
*
* @param e Entity to get Components with.
* @param array Array of Components to fill.
*/
public void getComponents(Entity e, Array array) {
Bits componentBits = e.getComponentBits();
for (int i = componentBits.nextSetBit(0); i >= 0; i = componentBits.nextSetBit(i+1)) {
array.add(componentsByType.get(i).get(e.id));
}
}
/**
* Returns an array of components for the specified entity.
* The Array is generated newly every time and making changes to its
* contents will not affect the components belonging to the entity.
*
* @param e Entity to get Components with.
* @return an array of components belonging to entity.
*/
public Array getComponents(Entity e) {
returnedComponents.clear();
getComponents(e, returnedComponents);
return returnedComponents;
}
@Override
public void deleted(Entity e) {
deletedEntities.add(e);
}
/**
* Cleans up deleted Entry's components. Need to do it separately
* to avoid freeing Components while other observers are processing
* the removal of an entity.
*/
public void clean() {
if (deletedEntities.size > 0) {
for (Entity entity : deletedEntities) {
removeComponentsOfEntity(entity);
}
deletedEntities.clear();
}
cleanRemovedComponents();
}
/**
* Cleans up components that have removed from the world.
*/
protected void cleanRemovedComponents() {
for (Entry entry : componentsToDelete.entries()) {
for (int i = 0; i < entry.value.size; i++) {
removeComponent(entry.key.id, entry.value.items[i]);
}
entry.value.clear();
Pools.free(entry.value);
}
componentsToDelete.clear();
}
/**
* Helper method to remove a Component for specified Entity and
* Component class index. Frees the Component to the pool.
*
* @param entityId Entity to remove the component for.
* @param componentClassIndex Component index to remove.
*/
protected void removeComponent(int entityId, int componentClassIndex) {
Array extends Component> components =
componentsByType.get(componentClassIndex);
if (components != null) {
Component compoment = components.get(entityId);
if (compoment != null) {
components.set(entityId, null);
Pools.free(compoment);
}
}
}
/**
* Retrieves a ComponentMapper instance for fast retrieval of
* components from entities.
*
* @param Type of component
* @param type of component to get mapper for.
* @return mapper for specified component type.
*/
@SuppressWarnings("unchecked")
public ComponentMapper getMapper(Class type) {
ComponentMapper mapper;
if (mappers.containsKey(type)) {
mapper = (ComponentMapper) mappers.get(type);
} else {
mapper = new ComponentMapper(type, world);
mappers.put(type, mapper);
}
return mapper;
}
@Override
public void dispose() {
for (Array extends Component> components : componentsByType) {
if (components != null) {
Pools.freeAll(components);
components.clear();
}
}
componentsByType.clear();
deletedEntities.clear();
mappers.clear();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy