r3-legacy/src/game-lib-entity-manager.js

513 lines
12 KiB
JavaScript

/**
* GameLib.EntityManager
* @constructor
*/
GameLib.EntityManager = function() {
this.id = GameLib.Utils.RandomId();
this.name = 'Entity Manager (' + this.id + ')';
this.entities = [];
GameLib.Component.call(
this,
GameLib.Component.COMPONENT_ENTITY_MANAGER,
{
'entities' : [GameLib.Entity]
},
null
);
this.loaded = [];
this.dependencies = {};
this.subscriptions = [];
this.registerCallbacks();
};
GameLib.EntityManager.prototype = Object.create(GameLib.Component.prototype);
GameLib.EntityManager.prototype.constructor = GameLib.EntityManager;
GameLib.EntityManager.prototype.createInstance = function() {
return GameLib.EntityManager.Instance;
};
/**
* Creates an GameLib.Entity and adds it to entities array
* @returns {*}
*/
GameLib.EntityManager.prototype.createEntity = function(name) {
var apiEntity = new GameLib.API.Entity(
null,
name,
null,
null,
this
);
var entity = new GameLib.Entity(
this.graphics,
apiEntity
);
this.entities.push(entity);
GameLib.Event.Emit(
GameLib.Event.NEW_ENTITY,
{
entity : entity
}
);
return entity;
};
/**
* Returns an entity by ID or null
* @param id
* @returns {*}
*/
GameLib.EntityManager.prototype.findEntityById = function(id) {
return this.entities.reduce(
function(result, entity){
if (entity.id === id) {
result = entity;
}
return result;
},
null
);
};
GameLib.EntityManager.prototype.findHelperByObject = function(object) {
return this.entities.reduce(
function(result, entity) {
var helpers = entity.getComponents(GameLib.D3.Helper);
var helper = helpers.reduce(
function(helperResult, tmpHelper) {
if (tmpHelper.object === object) {
helperResult = tmpHelper;
}
return helperResult;
},
null
);
if (helper) {
result = helper;
}
return result;
},
null
);
};
/**
* Adds an entity to this manager
* @param entity GameLib.Entity
*/
GameLib.EntityManager.prototype.addEntity = function(entity) {
entity.parentEntityManager = this;
this.entities.push(entity);
};
// /**
// * Adds a system to this manager
// * @param system GameLib.System
// */
// GameLib.EntityManager.prototype.addSystem = function(system) {
// this.systems.push(system);
// };
/**
* Returns entity by name
* @param name
* @returns {*}
*/
GameLib.EntityManager.prototype.queryByName = function(name) {
return this.entities.reduce(
function(result, entity){
if (entity.name === name) {
result = entity;
}
return result;
},
null
)
};
/**
* Removes an entity - do we remove all its components as well?
* @param entity GameLib.D3.Entity
* @returns boolean true if successful
*/
GameLib.EntityManager.prototype.removeEntity = function(entity) {
var index = this.entities.indexOf(entity);
if (index === -1) {
console.log('failed to remove entity : ', entity);
return false;
}
entity.parentEntityManager = null;
this.entities.splice(index, 1);
return true;
};
/**
* Returns all the entities with the following components
* @param components GameLib.Component[]
*/
GameLib.EntityManager.prototype.query = function(components) {
var entities = this.entities.reduce(
function(result, entity) {
var hasAllComponents = components.reduce(
function(componentResult, component) {
if (!entity.hasComponent(component)) {
componentResult = false;
}
return componentResult;
},
true
);
if (hasAllComponents) {
result.push(entity);
}
return result;
},
[]
);
return entities;
};
/**
* Returns all actual components of all entities that contain this component
* @param constructor
*/
GameLib.EntityManager.prototype.queryComponents = function(constructor) {
var entities = this.query([constructor]);
var components = entities.reduce(
function(result, entity){
var ecs = entity.getComponents(constructor);
ecs.map(function(ec){
result.push(ec);
});
return result;
},
[]
);
return components;
};
/**
* Converts a GameLib.Entity to GameLib.API.Entity
* @returns {GameLib.API.EntityManager}
*/
GameLib.EntityManager.prototype.toApiObject = function() {
var apiEntities = this.entities.map(
function (entity) {
return entity.toApiObject();
}
);
// var apiSystems = this.systems.map(
// function (system) {
// return system.toApiObject();
// }
// );
var apiEntityManager = new GameLib.API.EntityManager(
this.id,
this.name,
apiEntities,
// apiSystems,
this.parentEntity
);
return apiEntityManager;
};
/**
* Returns an EntityManager from an Object entity manager
* @param graphics
* @param objectEntityManager Object
* @constructor
*/
GameLib.EntityManager.FromObject = function(objectEntityManager) {
var apiEntityManager = GameLib.API.EntityManager.FromObject(objectEntityManager);
var entityManager = new GameLib.EntityManager(apiEntityManager);
return entityManager;
};
/**
* Defines what should happen when a parent scene changes
* @param data
*/
GameLib.EntityManager.prototype.onParentSceneChange = function(data) {
if (
data.object instanceof GameLib.D3.Mesh ||
data.object instanceof GameLib.D3.Light
) {
/**
* We remove the helper (if any) from the old scene and add it to the new scene
*/
var helper = this.findHelperByObject(data.object);
if (helper) {
if (data.originalScene && data.originalScene.instance) {
data.originalScene.instance.remove(helper.instance);
}
data.newScene.instance.add(helper.instance);
}
/**
* We remove the mesh from the old scene and add it to the new scene
*/
if (data.originalScene && data.originalScene.removeObject) {
data.originalScene.removeObject(data.object);
}
data.newScene.addObject(data.object);
/**
* We inherit the parent entity of this new scene
*/
var originalEntity = null;
var newEntity = null;
if (data.object.hasOwnProperty('parentEntity')) {
originalEntity = data.object.parentEntity
}
if (data.newScene.hasOwnProperty('parentEntity')) {
newEntity = data.newScene.parentEntity;
}
var gui = null;
if (originalEntity) {
if (originalEntity.removeComponent) {
if (helper) {
originalEntity.removeComponent(helper);
}
originalEntity.removeComponent(data.object);
}
if (originalEntity.getFirstComponent) {
gui = originalEntity.getFirstComponent(GameLib.GUI);
if (gui) {
gui.removeObject(data.object);
gui.build(this);
}
}
}
if (newEntity) {
if (newEntity.addComponent) {
if (helper) {
newEntity.addComponent(helper);
}
newEntity.addComponent(data.object);
}
if (newEntity.getFirstComponent) {
gui = newEntity.getFirstComponent(GameLib.GUI);
if (gui) {
gui.addObject(data.object);
gui.build(this);
}
}
}
}
};
/**
* Change parent entity
* TODO: also change parent entity of children objects
* @param data
*/
GameLib.EntityManager.prototype.onParentEntityChange = function(data) {
if (data.originalEntity) {
data.originalEntity.removeComponent(data.object);
}
data.newEntity.addComponent(data.object);
// - ok not so cool - we may have parent entities of entities -
// - so not all children should inherit the parent entity
// data.object.buildIdToObject();
//
// for (var property in data.object.idToObject) {
// if (data.object.idToObject.hasOwnProperty(property)) {
// if (data.object.idToObject[property].hasOwnProperty('parentEntity')) {
// data.object.idToObject[property].parentEntity = data.newEntity;
// }
// }
// }
};
GameLib.EntityManager.prototype.componentCreated = function(data) {
console.log('component created : ' + data.component.name);
/**
* If we notify ourselves - ignore it
*/
if (data.component === this) {
return;
}
/**
* Store this component into our 'loaded' list
*/
this.loaded.push(data.component);
/**
* Store the dependencies too
*/
data.component.dependencies.map(function(id) {
if (GameLib.Utils.UndefinedOrNull(this.dependencies[id])) {
this.dependencies[id] = [];
}
this.dependencies[id].push(data.component);
}.bind(this));
/**
* Now find all the dependencies of this component
*/
var dependencies = this.dependencies[data.component.id];
if (GameLib.Utils.UndefinedOrNull(dependencies)) {
/**
* We have no dependencies, so mark our component as loaded and create an instance
*/
data.component.loaded = true;
data.component.instance = data.component.createInstance();
/**
* If we have none, we are done and can exit
*/
return;
}
/**
* Otherwise, now - for each dependency - update 'idToObject' and check if its loaded
*/
dependencies.map(function(component){
component.idToObject[data.component.id] = data.component;
var loaded = true;
for (var property in component.idToObject) {
if (
component.idToObject.hasOwnProperty(property) &&
component.idToObject[property] === null
) {
loaded = false
}
}
component.loaded = loaded;
if (component.loaded) {
/**
* Our component is fully loaded, time to create an instance of it
*/
component.instance = component.createInstance();
}
})
};
/**
*
*/
GameLib.EntityManager.prototype.registerCallbacks = function() {
this.subscriptions.push(
this.subscribe(
GameLib.Event.PARENT_SCENE_CHANGE,
this.onParentSceneChange
)
);
this.subscriptions.push(
this.subscribe(
GameLib.Event.PARENT_ENTITY_CHANGE,
this.onParentEntityChange
)
);
this.subscriptions.push(
this.subscribe(
GameLib.Event.COMPONENT_CREATED,
this.componentCreated
)
);
};
/**
* Links object Ids to actual objects
* @param idToObject
*/
// GameLib.EntityManager.prototype.linkObjects = function(idToObject) {
//
// this.entities.map(
// function(entity) {
// entity.components.map(
// function (componentId, index, array) {
// if (componentId instanceof GameLib.Component) {
// array[index] = componentId;
// } else {
// array[index] = idToObject[componentId];
// }
//
// Object.keys(array[index].linkedObjects).map(
// function (propertyName) {
// array[index][propertyName] = idToObject[array[index][propertyName]];
// }
// );
//
// array[index].loaded = true;
// }
// )
// }
// );
//
// };