API Docs for:
Show:

File: ../src/World.js

(function(ArtemiJS) {
    'use strict';

    /**
     * The primary instance for the framework. It contains all the managers.
     * You must use this to create, delete and retrieve entities.
     * It is also important to set the delta each game loop iteration, 
     * and initialize before game loop.
     *
     * @module ArtemiJS
     * @class World
     * @constructor
     */
    var World = function() {
        
        /**
         * @private
         * @property entityManager
         * @type {EntityManager}
         */
        var entityManager = new ArtemiJS.EntityManager(),
        
        /**
         * @private
         * @property componentManager
         * @type {ComponentManager}
         */
        componentManager = new ArtemiJS.ComponentManager(),
        
        /**
         * @private
         * @property manager
         * @type {Object}
         */
        managers = {},
        
        /**
         * @private
         * @property managersBag
         * @type {Utils.Bag}
         */
        managersBag = new ArtemiJS.Utils.Bag(),
        
        /**
         * @private
         * @property systems
         * @type {Object}
         */
        systems = {},
        
        /**
         * @private
         * @property systemsBag
         * @type {Utils.Bag}
         */
        systemsBag = new ArtemiJS.Utils.Bag(),
    
        /**
         * @private
         * @property added
         * @type {Utils.Bag}
         */
        added = new ArtemiJS.Utils.Bag(),
        
        /**
         * @private
         * @property changed
         * @type {Utils.Bag}
         */
        changed = new ArtemiJS.Utils.Bag(),
        
        /**
         * @private
         * @property deleted
         * @type {Utils.Bag}
         */
        deleted = new ArtemiJS.Utils.Bag(),
        
        /**
         * @private
         * @property enable
         * @type {Utils.Bag}
         */
        enable = new ArtemiJS.Utils.Bag(),
        
        /**
         * @private
         * @property disable
         * @type {Utils.Bag}
         */
        disable = new ArtemiJS.Utils.Bag(),
    
        /**
         * @private
         * @property delta
         * @type {Number}
         */
        delta = 0;
    
        this.setManager(componentManager);
        this.setManager(entityManager);
        
        /**
         * Makes sure all managers systems are initialized in the order 
         * they were added
         * 
         * @method initialize
         */
        this.initialize = function() {
            var i = managersBag.size();
            while(i--) {
                managersBag.get(i).initialize();
            }
            i = systemsBag.size();
            while(i--) {
                systemsBag.get(i).initialize();
            }
        };
        
        /**
         * Returns a manager that takes care of all the entities in the world.
         * entities of this world
         * 
         * @method getEntityManager
         * @return {EntityManager} entityManager
         */
        this.getEntityManager = function() {
            return entityManager;
        };
        
        /**
         * Returns a manager that takes care of all the components in the world.
         * 
         * @method getComponentManager
         * @return {ComponentManager} componentManager
         */
        this.getComponentManager = function() {
            return componentManager;
        };
        
        /**
         * Add a manager into this world. It can be retrieved later.
         * World will notify this manager of changes to entity.
         * 
         * @method setManager
         * @param {Manager} manager manager to be added
         * @return {Manager} manager
         */
        this.setManager = function(manager) {
            manager.setWorld(this);
            
            managers[manager.getClass()] = manager;
            managersBag.add(manager);
    
            return manager;
        };
        
        /**
         * Returns a manager of the specified type.
         * 
         * @param {String} managerType class type of the manager
         * @return {Manager} manager
         */
        this.getManager = function(managerType) {        
            return managers[managerType] || false;
        };
        
        /**
         * Deletes the manager from this world.
         * 
         * @method deleteManager
         * @param {Manager} manager manager to delete.
         */
        this.deleteManager = function(manager) {
            delete managers[manager.getClass()];
            managersBag.remove(manager);
        };
        
        /**
         * You must specify the delta for the game here.
         * 
         * @method setDelta
         * @param {Number} d time since last game loop.
         */
        this.setDelta = function(d) {
            delta = d;
        };
        
        /**
         * 
         * @method getDelta
         * @return {Number} delta time since last game loop.
         */
        this.getDelta = function() {
            return delta;
        };
        
        /**
         * Adds a entity to this world.
         * 
         * @method addEntity
         * @param {Entity} entity
         */
        this.addEntity = function(entity) {
            added.add(entity);
        };
        
        /**
         * Ensure all systems are notified of changes to this entity.
         * If you're adding a component to an entity after it's been
         * added to the world, then you need to invoke this method.
         * 
         * @method changedEntity
         * @param {Entity} entity
         */
        this.changedEntity = function(entity) {
            changed.add(entity);
        };
        
        /**
         * Delete the entity from the world.
         * 
         * @method deleteEntity
         * @param {Entity} entity
         */
        this.deleteEntity = function(entity) {
            added.remove(entity);
        };
        
        /**
         * (Re)enable the entity in the world, after it having being disabled.
         * Won't do anything unless it was already disabled.
         * 
         * @method enableEntity
         * @param {Entity} entity
         */
        this.enableEntity = function(entity) {
            enable.add(entity);
        };
        
        /**
         * Disable the entity from being processed. Won't delete it, it will
         * continue to exist but won't get processed.
         * 
         * @method disableEntity
         * @param {Entity} entity
         */
        this.disableEntity = function(entity) {
            disable.add(entity);
        };
        
        /**
         * Create and return a new or reused entity instance.
         * Will NOT add the entity to the world, use World.addEntity(Entity) for that.
         * 
         * @method createEntity
         * @return {Entity} entity
         */
        this.createEntity = function() {
            return entityManager.createEntityInstance();
        };
        
        /**
         * Get a entity having the specified id.
         * 
         * @method getEntity
         * @param {Number} entityId
         * @return {Entity} entity
         */
        this.getEntity = function(id) {
            return entityManager.getEntity(id);
        };
        
        /**
         * Gives you all the systems in this world for possible iteration.
         * 
         * @method getSystems
         * @return {Mixed} all entity systems in world, other false
         */
        this.getSystems = function() {
            return systemsBag;
        }
        
        /**
         * Adds a system to this world that will be processed by World.process()
         * 
         * @method setSystem
         * @param {EntitySystem} system the system to add.
         * @param {Boolean} [passive] wether or not this system will be processed by World.process()
         * @return {EntitySystem} the added system.
         */
        this.setSystem = function(system, passive) {
            passive = passive || false;
            
            system.setWorld(this);
            system.setPassive(passive);
            
            systems[system.getClass()] = system;
            systemsBag.add(system);
            
            return system;
        };
    
        /**
         * Retrieve a system for specified system type.
         * 
         * @method getSystem
         * @param {String} systemType type of system.
         * @return {EntitySystem} instance of the system in this world.
         */
        this.getSystem = function(systemType) {        
            return systems[systemType] || false;
        };
        
        /**
         * Removed the specified system from the world.
         * 
         * @method deleteSystem
         * @param system to be deleted from world.
         */
        this.deleteSystem = function(system) {
            delete systems[system.getClass()];
            systemsBag.remove(system);
        };
        
        /**
         * Notify all the systems
         * 
         * @private
         * @method notifySystems
         * @param {Object} performer Object with callback perform
         * @param {Entity} entity
         */
        function notifySystems(performer, entity) {
            var i = systemsBag.size();
            while(i--) {
                performer.perform(systemsBag.get(i), entity);
            }        
        }
        
        /**
         * Notify all the managers
         * 
         * @private
         * @method notifySystems
         * @param {Object} performer Object with callback perform
         * @param {Entity} entity
         */
        function notifyManagers(performer, entity) {
            var i = managersBag.size();
            while(i--) {
                performer.perform(managersBag.get(i), entity);
            }
        }
        
        /**
         * Performs an action on each entity.
         * 
         * @private
         * @method check
         * @param {Utils.Bag} entities
         * @param {Object} performer
         */
        function check(entities, performer) {
            if(!entities.size()) {
                return;
            }
            var i = entities.size();
            while(i--) {
                var entity = entities.get(i);
                notifyManagers(performer, entity);
                notifySystems(performer, entity);
            }
            
            entities.clear();
        }
        
        /**
         * Process all non-passive systems.
         * 
         * @method process
         */
        this.process = function() {
            
            check(added, {
                perform: function(observer, entity) {
                    observer.added(entity);
                }
            });
            
            check(changed, {
                perform: function(observer, entity) {
                    observer.changed(entity);
                }
            });
            
            check(disable, {
                perform: function(observer, entity) {
                    observer.disabled(entity);
                }
            });
            
            check(enable, {
                perform: function(observer, entity) {
                    observer.enabled(entity);
                }
            });
            
            check(deleted, {
                perform: function (observer, entity) {
                    observer.deleted(entity);
                }
            });
            
            componentManager.clean();
            
            var i = systemsBag.size();
            while(i--) {
                var system = systemsBag.get(i);
                if(!system.isPassive()) {
                    system.process();
                }
            }
        };
        
        /**
         * Retrieves a ComponentMapper instance for fast retrieval 
         * of components from entities.
         * 
         * @method getMapper
         * @param {Object} type of component to get mapper for.
         * @return {ComponentMapper} mapper for specified component type.
         */
        this.getMapper = function(type) {
            return ArtemiJS.ComponentMapper.getFor(type, this);
        };
    };
    
    ArtemiJS.World = World;
})(window.ArtemiJS || {});