ecsy
Version:
Entity Component System in JS
238 lines (193 loc) • 7.39 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Not = Not;
exports.System = void 0;
var _Query = _interopRequireDefault(require("./Query.js"));
var _Utils = require("./Utils.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
class System {
canExecute() {
if (this._mandatoryQueries.length === 0) return true;
for (let i = 0; i < this._mandatoryQueries.length; i++) {
var query = this._mandatoryQueries[i];
if (query.entities.length === 0) {
return false;
}
}
return true;
}
getName() {
return this.constructor.getName();
}
constructor(world, attributes) {
this.world = world;
this.enabled = true; // @todo Better naming :)
this._queries = {};
this.queries = {};
this.priority = 0; // Used for stats
this.executeTime = 0;
if (attributes && attributes.priority) {
this.priority = attributes.priority;
}
this._mandatoryQueries = [];
this.initialized = true;
if (this.constructor.queries) {
for (var queryName in this.constructor.queries) {
var queryConfig = this.constructor.queries[queryName];
var Components = queryConfig.components;
if (!Components || Components.length === 0) {
throw new Error("'components' attribute can't be empty in a query");
} // Detect if the components have already been registered
let unregisteredComponents = Components.filter(Component => !(0, _Utils.componentRegistered)(Component));
if (unregisteredComponents.length > 0) {
throw new Error(`Tried to create a query '${this.constructor.name}.${queryName}' with unregistered components: [${unregisteredComponents.map(c => c.getName()).join(", ")}]`);
}
var query = this.world.entityManager.queryComponents(Components);
this._queries[queryName] = query;
if (queryConfig.mandatory === true) {
this._mandatoryQueries.push(query);
}
this.queries[queryName] = {
results: query.entities
}; // Reactive configuration added/removed/changed
var validEvents = ["added", "removed", "changed"];
const eventMapping = {
added: _Query.default.prototype.ENTITY_ADDED,
removed: _Query.default.prototype.ENTITY_REMOVED,
changed: _Query.default.prototype.COMPONENT_CHANGED // Query.prototype.ENTITY_CHANGED
};
if (queryConfig.listen) {
validEvents.forEach(eventName => {
if (!this.execute) {
console.warn(`System '${this.getName()}' has defined listen events (${validEvents.join(", ")}) for query '${queryName}' but it does not implement the 'execute' method.`);
} // Is the event enabled on this system's query?
if (queryConfig.listen[eventName]) {
let event = queryConfig.listen[eventName];
if (eventName === "changed") {
query.reactive = true;
if (event === true) {
// Any change on the entity from the components in the query
let eventList = this.queries[queryName][eventName] = [];
query.eventDispatcher.addEventListener(_Query.default.prototype.COMPONENT_CHANGED, entity => {
// Avoid duplicates
if (eventList.indexOf(entity) === -1) {
eventList.push(entity);
}
});
} else if (Array.isArray(event)) {
let eventList = this.queries[queryName][eventName] = [];
query.eventDispatcher.addEventListener(_Query.default.prototype.COMPONENT_CHANGED, (entity, changedComponent) => {
// Avoid duplicates
if (event.indexOf(changedComponent.constructor) !== -1 && eventList.indexOf(entity) === -1) {
eventList.push(entity);
}
});
} else {
/*
// Checking just specific components
let changedList = (this.queries[queryName][eventName] = {});
event.forEach(component => {
let eventList = (changedList[
componentPropertyName(component)
] = []);
query.eventDispatcher.addEventListener(
Query.prototype.COMPONENT_CHANGED,
(entity, changedComponent) => {
if (
changedComponent.constructor === component &&
eventList.indexOf(entity) === -1
) {
eventList.push(entity);
}
}
);
});
*/
}
} else {
let eventList = this.queries[queryName][eventName] = [];
query.eventDispatcher.addEventListener(eventMapping[eventName], entity => {
// @fixme overhead?
if (eventList.indexOf(entity) === -1) eventList.push(entity);
});
}
}
});
}
}
}
}
stop() {
this.executeTime = 0;
this.enabled = false;
}
play() {
this.enabled = true;
} // @question rename to clear queues?
clearEvents() {
for (let queryName in this.queries) {
var query = this.queries[queryName];
if (query.added) {
query.added.length = 0;
}
if (query.removed) {
query.removed.length = 0;
}
if (query.changed) {
if (Array.isArray(query.changed)) {
query.changed.length = 0;
} else {
for (let name in query.changed) {
query.changed[name].length = 0;
}
}
}
}
}
toJSON() {
var json = {
name: this.getName(),
enabled: this.enabled,
executeTime: this.executeTime,
priority: this.priority,
queries: {}
};
if (this.constructor.queries) {
var queries = this.constructor.queries;
for (let queryName in queries) {
let query = this.queries[queryName];
let queryDefinition = queries[queryName];
let jsonQuery = json.queries[queryName] = {
key: this._queries[queryName].key
};
jsonQuery.mandatory = queryDefinition.mandatory === true;
jsonQuery.reactive = queryDefinition.listen && (queryDefinition.listen.added === true || queryDefinition.listen.removed === true || queryDefinition.listen.changed === true || Array.isArray(queryDefinition.listen.changed));
if (jsonQuery.reactive) {
jsonQuery.listen = {};
const methods = ["added", "removed", "changed"];
methods.forEach(method => {
if (query[method]) {
jsonQuery.listen[method] = {
entities: query[method].length
};
}
});
}
}
}
return json;
}
}
exports.System = System;
System.isSystem = true;
System.getName = function () {
return this.displayName || this.name;
};
function Not(Component) {
return {
operator: "not",
Component: Component
};
}