Skip to content

Commit

Permalink
Added onCreate to components
Browse files Browse the repository at this point in the history
The entity is passed to onCreate, to be able to get the ID or other components in that entity
Added "get" to world, which returns an array of matching entities
Various refactoring, added an invoke function
Simplified every() method, got rid of "this" hacks by using "bind"
Updated to v0.2.6
  • Loading branch information
ayebear committed May 24, 2017
1 parent 3fb42b0 commit 2b224c4
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "picoes",
"version": "0.2.5",
"version": "0.2.6",
"description": "Pico Entity System for JavaScript (ES6).",
"main": "./src/picoes.js",
"scripts": {
Expand Down
12 changes: 8 additions & 4 deletions src/entity.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
let invoke = require('./utilities.js').invoke

// Entity class used internally for keeping track of components
class Entity {
constructor(world, id) {
Expand Down Expand Up @@ -43,6 +45,9 @@ class Entity {
if (this.valid() && component in this.world.components) {
// Use defined component template
this.data[component] = new this.world.components[component](...args)

// Call custom onCreate with this entity as a parameter
invoke(this.data[component], 'onCreate', this)
} else if (args.length > 0) {
// Use first argument as component value
this.data[component] = args[0]
Expand Down Expand Up @@ -82,10 +87,9 @@ class Entity {
this.world.index.remove(this, component)
}

let comp = this.data[component]
if (typeof comp.onRemove === 'function') {
comp.onRemove()
}
// Call custom onRemove
invoke(this.data[component], 'onRemove')

delete this.data[component]
}
return this
Expand Down
38 changes: 18 additions & 20 deletions src/picoes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
let invoke = require('./utilities.js').invoke
let Entity = require('./entity.js').Entity
let Index = require('./index.js').Index

Expand Down Expand Up @@ -78,8 +79,11 @@ class World {
// world.system(class { every(ent) {} })
system(components, systemClass, ...args) {
if (isFunction(systemClass)) {
// Create the system, and set the component array query
let newSystem = new systemClass(...args)
newSystem.components = components

// Add the system, return its ID
this.systems.push(newSystem)
return this.systems.length - 1
}
Expand All @@ -89,35 +93,29 @@ class World {
// Calls initialize() on all systems
initialize(...args) {
for (let system of this.systems) {
if (isFunction(system.initialize)) {
system.initialize.call(system, ...args)
}
invoke(system, 'initialize', ...args)
}
}

// Calls pre, every, and post on all systems
run(...args) {
for (let system of this.systems) {
if (isFunction(system.pre)) {
system.pre.call(system, ...args)
}
invoke(system, 'pre', ...args)

// Run the "every" method in the system
if (isFunction(system.every)) {
this.every(system.components, system.every, system, ...args)
this.every(system.components, system.every.bind(system), ...args)
}

if (isFunction(system.post)) {
system.post.call(system, ...args)
}
invoke(system, 'post', ...args)
}
}

// Iterate through entities with the specified components
// world.every(['comp'], comp => {comp.value = 0})
// Get an iterator for the entities
// let it = world.every(['comp'])
every(componentNames, callback, that, ...args) {
every(componentNames, callback, ...args) {
// Get indexed map of entities
let entities = this.index.query(componentNames)

Expand All @@ -131,22 +129,22 @@ class World {
// Get all components as an array
let comps = componentNames.map(name => ent.get(name))

// Add entity itself then any additional arguments after the components
comps.push(ent, ...args)

// Expand array as parameters to the method
if (that === undefined) {
callback(...comps)
} else {
callback.call(that, ...comps)
}
// Pass components, then the main entity, then any additional arguments
callback(...comps, ent, ...args)
}
}
}

return entities.values()
}

// Returns an array of entities with matching components
// Simplified version of every(), returns an actual array, and only takes component names as arguments
// world.get('player', 'sprite')
get(...componentNames) {
return [...this.every([...componentNames])]
}

// Registers entity prototype(s)
// Must be either a string or an object
// Top level must be prototype names
Expand Down
7 changes: 7 additions & 0 deletions src/utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function invoke(object, method, ...args) {
if (object && typeof object[method] === 'function') {
return object[method].call(object, ...args)
}
}

exports.invoke = invoke
16 changes: 16 additions & 0 deletions test/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ describe('World', function() {
})
assert(count === 0)
})
it('test entity creation with onCreate', function() {
let world = new World()
world.component('sprite', class {
onCreate(entity) {
this.entity = entity
this.x = 1
}
})

let ent = world.entity().set('sprite')
assert(ent.get('sprite').entity === ent)
assert(ent.get('sprite').x === 1)
})
it('test clearing with onRemove', function() {
let spriteCount = 0
let world = new World()
Expand Down Expand Up @@ -216,6 +229,8 @@ describe('World', function() {
assert(spriteCount === 2)
assert(Object.keys(world.entities).length === 1)
assert(getSize(world.every(['position'])) === 1)
assert(world.get('position').length === 1)
assert(world.get('position')[0].get('position').x === 2)
assert(ent.get('position').x === 1)

// Test attaching
Expand All @@ -224,6 +239,7 @@ describe('World', function() {
assert(spriteCount === 2)
assert(Object.keys(world.entities).length === 2)
assert(getSize(world.every(['position'])) === 2)
assert(world.get('position').length === 2)
assert(ent.get('position').x === 1)

// Test edge cases
Expand Down

0 comments on commit 2b224c4

Please sign in to comment.