All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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 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 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 components : componentsByType) {
            if (components != null) {
                Pools.freeAll(components);
                components.clear();
            }
        }
        componentsByType.clear();
        deletedEntities.clear();
        mappers.clear();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy