UNPKG

javascript-entity-component-system

Version:
1 lines 15.8 kB
{"mappings":"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","sources":["src/src/index.ts","src/index.ts"],"sourcesContent":[null,"export type Component = {\r\n name : string\r\n state : {\r\n [key: string]: any\r\n }\r\n onAttach?: Function\r\n}\r\n\r\nexport type Processor = {\r\n name : string\r\n required: string[]\r\n update(entity: Entity, components: Component[], processor: Processor): void\r\n}\r\n\r\nexport type Entity = {\r\n name : string\r\n components: Component[]\r\n processors: Processor[]\r\n}\r\n\r\n/**\r\n * The Entity Component System class.\r\n */\r\nexport class EntityComponentSystem {\r\n /**\r\n * All registered components\r\n * @defaultValue []\r\n */\r\n components: Component[]\r\n\r\n /**\r\n * All registered processors\r\n * @defaultValue []\r\n */\r\n processors: Processor[]\r\n\r\n /**\r\n * All registered entities\r\n * @defaultValue []\r\n */\r\n entities: Entity[]\r\n\r\n constructor() {\r\n this.components = []\r\n this.processors = []\r\n this.entities = []\r\n }\r\n\r\n /**\r\n * Gets all registered processors.\r\n * @returns All registered processors in an array.\r\n */\r\n getProcessors(): Processor[] {\r\n return this.processors\r\n }\r\n\r\n /**\r\n * Gets all components processors.\r\n * @returns All registered components in an array.\r\n */\r\n getComponents(): Component[] {\r\n return this.components\r\n }\r\n\r\n /**\r\n * Gets all registered entities.\r\n * @returns All registered entities in an array.\r\n */\r\n getEntities(): Entity[] {\r\n return this.entities\r\n }\r\n\r\n /**\r\n * Gets a registered processor by name.\r\n * @param name - Name of the processor\r\n * @returns A processor or throws an error.\r\n */\r\n getProcessor(name: string): Processor {\r\n const hasProcessor = this.hasProcessor(name)\r\n\r\n if (!hasProcessor) {\r\n throw new Error(`getProcessor(): processor \"${name}\" not found.`)\r\n }\r\n\r\n return this.processors.find((processor) => processor.name === name) as Processor\r\n }\r\n\r\n /**\r\n * Gets a registered component by name.\r\n * @param name - Name of the component\r\n * @returns A component or throws an error.\r\n */\r\n getComponent(name: string): Component {\r\n const hasComponent = this.hasComponent(name)\r\n\r\n if (!hasComponent) {\r\n throw new Error(`getComponent(): component \"${name}\" not found.`)\r\n }\r\n\r\n return this.components.find((component) => component.name === name) as Component\r\n }\r\n\r\n /**\r\n * Gets a registered entity by name.\r\n * @param name -Name of the entity\r\n * @returns A entity or throws an error. \r\n */\r\n getEntity(name: string): Entity {\r\n const hasEntity = this.hasEntity(name)\r\n\r\n if (!hasEntity) {\r\n throw new Error(`getEntity(): entity \"${name}\" not found.`)\r\n }\r\n\r\n return this.entities.find((entity) => entity.name === name) as Entity\r\n }\r\n\r\n /**\r\n * Gets all registered entities that match the given name.\r\n * @param name -Name of the entity\r\n * @returns An array of entities or an empty array.\r\n */\r\n getEntitiesByName(name: string): Entity[] {\r\n const entities = []\r\n const length = this.entities.length\r\n\r\n for (let i = 0; i < length; i++) {\r\n const currentEntity = this.entities[i]\r\n\r\n if (currentEntity.name === name) {\r\n entities.push(currentEntity)\r\n }\r\n }\r\n \r\n return entities\r\n }\r\n\r\n getEntityComponents(entity: Entity, components: string[]): Component[] {\r\n const foundComponents = []\r\n const length = entity.components.length\r\n\r\n for (let currentComponent of components) {\r\n for (let i = 0; i < length; i++) {\r\n const currentEntityComponent = entity.components[i]\r\n\r\n if (currentEntityComponent.name === currentComponent) {\r\n foundComponents.push(currentEntityComponent)\r\n }\r\n }\r\n }\r\n\r\n return foundComponents\r\n }\r\n\r\n /**\r\n * Checks if processor is registered by name.\r\n * @param name - Name of the processor\r\n * @returns true if found or false if not.\r\n */\r\n hasProcessor(name: string): boolean {\r\n let found = false\r\n\r\n for (let processor of this.processors) {\r\n if (processor.name === name) {\r\n found = true\r\n }\r\n }\r\n\r\n return found\r\n }\r\n\r\n /**\r\n * Checks if component is registered.\r\n * @param name - Name of the component\r\n * @returns true if found or false if not.\r\n */\r\n hasComponent(name: string): boolean {\r\n let found = false\r\n\r\n for (let component of this.components) {\r\n if (component.name === name) {\r\n found = true\r\n }\r\n }\r\n\r\n return found\r\n }\r\n\r\n /**\r\n * Checks if entity is registered.\r\n * @param name - Name of the entity\r\n * @returns true if found or false if not.\r\n */\r\n hasEntity(name: string): boolean {\r\n let found = false\r\n\r\n for (let entity of this.entities) {\r\n if (entity.name === name) {\r\n found = true\r\n }\r\n }\r\n\r\n return found\r\n }\r\n\r\n /**\r\n * Composes a entity with given components.\r\n * @param name - Name of the entity\r\n * @param components - An array of component names\r\n * @param processors - An array of processor names\r\n * @returns The composed entity or throws an error.\r\n */\r\n createEntity(name: string, components: string[], processors: string[]): Entity {\r\n const entityName = name\r\n const allComponents = []\r\n const allProcessors = []\r\n\r\n components.forEach(componentName => {\r\n const foundComponent = this.getComponent(componentName)\r\n const copy = JSON.parse(JSON.stringify(foundComponent))\r\n\r\n if (copy.onAttach) {\r\n foundComponent.onAttach()\r\n }\r\n\r\n allComponents.push(copy)\r\n })\r\n\r\n processors.forEach(processorName => {\r\n const foundProcessor = this.getProcessor(processorName)\r\n\r\n allProcessors.push(foundProcessor)\r\n })\r\n\r\n return {\r\n name: entityName,\r\n components: allComponents,\r\n processors: allProcessors\r\n }\r\n }\r\n\r\n /**\r\n * Checks if an entity has target component.\r\n * @param entity - entity object\r\n * @param component - Name of component\r\n * @returns true if entity has the component or false if not\r\n */\r\n entityHasComponent(entity: Entity, component: string): boolean {\r\n const length = entity.components.length\r\n\r\n for (let i = 0; i < length; i++) {\r\n if (entity.components[i].name === component) {\r\n return true\r\n }\r\n }\r\n\r\n return false\r\n }\r\n\r\n /**\r\n * Checks if an entity has target processor.\r\n * @param entity - entity object\r\n * @param processor - Name of processor\r\n * @returns true if entity has the processor or false if not\r\n */\r\n entityHasProcessor(entity: Entity, processor: string): boolean {\r\n const length = entity.processors.length\r\n\r\n for (let i = 0; i < length; i++) {\r\n if (entity.processors[i].name === processor) {\r\n return true\r\n }\r\n }\r\n\r\n return false\r\n }\r\n\r\n /**\r\n * Removes a component from an entity.\r\n * @param entity - entity object\r\n * @param component - Name of component\r\n * @returns Void if operation successful or throw an error.\r\n */\r\n removeComponentFromEntity(entity: Entity, component: string): void {\r\n if (!this.entityHasComponent(entity, component)) {\r\n throw new Error(`removeComponentFromEntity(): component ${component} not found in entity ${entity.name}`)\r\n }\r\n\r\n let index = null\r\n const length = entity.components.length\r\n\r\n for (let i = 0; i < length; i++) {\r\n if (entity.components[i].name === component) {\r\n index = i\r\n break\r\n }\r\n }\r\n\r\n entity.components.splice(index, 1)\r\n }\r\n\r\n /**\r\n * Removes processor from an entity.\r\n * @param entity - entity object\r\n * @param processor - Name of processor\r\n * @returns Void if operation successful or throws an error.\r\n */\r\n removeProcessorFromEntity(entity: Entity, processor: string): void {\r\n if (!this.entityHasProcessor(entity, processor)) {\r\n throw new Error(`removeProcessorFromEntity(): Processor ${processor} not found in entity ${entity.name}`)\r\n }\r\n\r\n let index = null\r\n const length = entity.processors.length\r\n\r\n for (let i = 0; i < length; i++) {\r\n if (entity.processors[i].name === processor) {\r\n index = i\r\n break\r\n }\r\n }\r\n\r\n entity.processors.splice(index, 1)\r\n }\r\n\r\n /**\r\n * Adds a component to an entity.\r\n * @param entity - entity object\r\n * @param component - Name of component\r\n * @returns Void if operation is successful or throws an error.\r\n */\r\n addComponentToEntity(entity: Entity, component: string): void {\r\n if (this.entityHasComponent(entity, component)) {\r\n throw new Error(`addComponentToEntity(): Can't add component ${component} - this entity already has this component.`)\r\n }\r\n\r\n if (!this.hasComponent(component)) {\r\n throw new Error(`addComponentToEntity(): You can't add component ${component} to entity ${entity.name}, because the component is not registered.`)\r\n }\r\n\r\n entity.components.push(this.getComponent(component))\r\n }\r\n\r\n /**\r\n * Adds a processor to an entity.\r\n * @param entity - entity object\r\n * @param processor - Name of processor\r\n * @returns Void if operation is successful or throws an error.\r\n */\r\n addProcessorToEntity(entity: Entity, processor: string): void {\r\n if (this.entityHasProcessor(entity, processor)) {\r\n throw new Error(`addProcessorToEntity(): Can't add processor ${processor} - this entity already this processor.`)\r\n }\r\n\r\n if (!this.hasProcessor(processor)) {\r\n throw new Error(`addProcessorToEntity(): You can't add processor ${processor} to entity ${entity.name}, because the processor is not registerd.`)\r\n }\r\n\r\n entity.processors.push(this.getProcessor(processor))\r\n }\r\n\r\n /**\r\n * Adds a entity to the system.\r\n * @param entity - entity object\r\n * @returns Void if successful\r\n */\r\n addEntity(entity: Entity): void {\r\n this.entities.push(entity)\r\n }\r\n\r\n /**\r\n * Adds a component to the system.\r\n * @param component - component object\r\n * @returns Void if successful\r\n */\r\n addComponent(component: Component): void {\r\n const passedComponent = component as Component\r\n\r\n if (passedComponent.onAttach) {\r\n passedComponent.onAttach()\r\n }\r\n\r\n this.components.push(passedComponent)\r\n }\r\n\r\n /**\r\n * Adds a processor to the system.\r\n * @param processor - processor object\r\n * @returns Void if successful\r\n */\r\n addProcessor(processor: Processor): void {\r\n this.processors.push(processor)\r\n }\r\n\r\n /**\r\n * Removes an entity from the system.\r\n * @param entity - entity object\r\n * @returns Void if successful or throws an error.\r\n */\r\n removeEntity(entity: Entity): void {\r\n const length = this.entities.length\r\n\r\n for (let i = 0; i < length; i++) {\r\n if (this.entities[i] === entity) {\r\n this.entities.splice(i, 1)\r\n return\r\n }\r\n }\r\n\r\n throw new Error(`removeEntity(): entity \"${entity.name}\" not found.`)\r\n }\r\n\r\n\r\n /**\r\n * Removes all entities from the system.\r\n * @returns void\r\n */\r\n removeAllEntities(): void {\r\n this.entities = []\r\n }\r\n\r\n /**\r\n * Gets all entities that have the target component registered.\r\n * @param componentName - Name of the component\r\n * @returns All entities in an array.\r\n */\r\n private getEntitiesFromRequiredComponents(components: string[]): Entity[] {\r\n const entities = []\r\n let entitiesAmount = this.entities.length\r\n\r\n for (let i = 0; i < entitiesAmount; i++) {\r\n const currentEntity = this.entities[i]\r\n let hasAllComponents = true\r\n\r\n for (let j = 0; j < components.length; j++) {\r\n const currentComponent = components[j]\r\n \r\n if (!this.entityHasComponent(currentEntity, currentComponent)) {\r\n hasAllComponents = false\r\n break\r\n }\r\n }\r\n\r\n if (hasAllComponents) {\r\n entities.push(currentEntity)\r\n }\r\n }\r\n\r\n return entities\r\n }\r\n\r\n\r\n /**\r\n * Runs all processors for it's corresponding components e.g. run the prcoessors update function.\r\n * @returns Void if successful\r\n */\r\n private runProcessors(): void {\r\n this.processors.forEach(processor => {\r\n const entities = this.getEntitiesFromRequiredComponents(processor.required)\r\n const entityAmount = entities.length\r\n\r\n for (let i = 0; i < entityAmount; i++) {\r\n const currentEntity = entities[i]\r\n const hasProcessor = this.entityHasProcessor(currentEntity, processor.name)\r\n\r\n if (hasProcessor) {\r\n const components = this.getEntityComponents(currentEntity, processor.required)\r\n processor.update(currentEntity, components, processor)\r\n }\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * Runs all processors. This should be done per frame e.g. inside your gameloop.\r\n * @returns Void if successful\r\n */\r\n update(): void {\r\n this.runProcessors()\r\n }\r\n}"],"names":[],"version":3,"file":"types.d.ts.map"}