513 lines
12 KiB
JavaScript
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;
|
|
// }
|
|
// )
|
|
// }
|
|
// );
|
|
//
|
|
// };
|