Skip to content

Commit

Permalink
implement core engine functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
sz-piotr committed Aug 13, 2017
1 parent 7fbf752 commit 199d560
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 18 deletions.
2 changes: 1 addition & 1 deletion lib/ouyo.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/ouyo.js.map

Large diffs are not rendered by default.

106 changes: 98 additions & 8 deletions src/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@ import { Entity } from './entity'
export class Engine {
constructor() {
this.entities = null
this.dirtyEntites = []
this.changed = []
this.removed = []

this.systems = []
this.queries = []
this.componentIdMap = []
this.componentsCount = 0

this.configurable = true
this.started = false
this.running = false

this.onEntityKeyChange = this.onEntityKeyChange.bind(this)
}

createEntity() {
this.configurable = false
if(!this.started) {
throw new Error('Entities cannot be added before the engine is started.')
}

const entity = new Entity(
this.componentsCount,
this.componentIdMap,
Expand All @@ -31,6 +37,10 @@ export class Engine {
}

removeEntity(entity) {
if(!this.started) {
throw new Error('Entities cannot be removed before the engine is started.')
}

const next = entity.next
const prev = entity.prev

Expand All @@ -47,14 +57,16 @@ export class Engine {
if(this.entities = entity) {
this.entities = next
}

this.removed.push(entity)
}

onEntityKeyChange(entity) {
this.dirtyEntites.push(entity)
this.changed.push(entity)
}

registerSystem({ query, sort, update, processEntity }) {
if(!this.configurable) {
if(this.started) {
throw new Error('Cannot register system after entities have been added or the engine was started.')
}

Expand All @@ -66,19 +78,30 @@ export class Engine {
throw new Error('"processEntity" can only be used with a query.')
}

this.systems.push({
if(!query && sort) {
throw new Error('"sort" can only be used with a query.')
}

const system = {
query: query ? query.bake(this) : false,
sort,
sorted: [],
update: update || function(entities, timeDelta, engine) {
for(let i = 0; i < entities.length; ++i) {
processEntity(entities[i], timeDelta, engine)
}
}
})
}

this.systems.push(system)

if(system.query) {
this.queries.push(system.query)
}
}

registerComponent(component) {
if(!this.configurable) {
if(this.started) {
throw new Error('Cannot register component after entities have been added or the engine was started.')
}

Expand All @@ -90,8 +113,75 @@ export class Engine {
this.componentIdMap[component.id] = this.componentsCount++
}
}

start(init) {
// TODO: add pause
this.started = true
this.running = true
if(init) {
init(this)
}

let now
let lastTime = Date.now()
const tick = () => {
if(this.running) {
now = Date.now()
this.update((now - lastTime) / 60)
lastTime = now
}
requestAnimationFrame(tick)
}
requestAnimationFrame(tick)
}

update(timeDelta) {
for(let i = 0; i < systems.length; ++i) {
this.runSystem(systems[i], timeDelta)
this.handleChanges()
}
}

runSystem(system, timeDelta) {
if(system.query) {
let entities = system.query.entities
if(system.sort) {
copyArray(entities, system.sorted)
entities = system.sorted
entities.sort(system.sort)
}
system.update(entities, timeDelta, this)
} else {
system.update(timeDelta, this)
}
}

handleChanges() {
for(let i = 0; i < this.changed.length; i++) {
let changed = this.changed[i]
for(let j = 0; j < this.queries.length; j++) {
this.queries[j].onChange(changed)
}
}
this.changed.length = 0

for(let i = 0; i < this.removed.length; i++) {
let removed = this.removed[i]
for(let j = 0; j < this.queries.length; j++) {
this.queries[j].onRemove(removed)
}
}
this.changed.length = 0
}
}

function bothOrNone(a, b) {
return (a && b) || (!a && !b)
}

function copyArray(from, to) {
for(let i = 0; i < from.length; ++i) {
to[i] = from[i]
}
to.length = from.length
}
16 changes: 8 additions & 8 deletions src/engine.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ describe('Engine', () => {
})

test('createEntity() should create an entity', () => {
expect(new Engine().createEntity()).toBeInstanceOf(Entity)
const engine = new Engine()
engine.started = true
expect(engine.createEntity()).toBeInstanceOf(Entity)
})

test('createEntity() should form a linked list', () => {
const engine = new Engine()
engine.started = true
const e1 = engine.createEntity()
const e2 = engine.createEntity()
const e3 = engine.createEntity()
Expand All @@ -26,15 +29,9 @@ describe('Engine', () => {
expect(e3.prev).toBe(null)
})

test('createEntity() should disable configuration', () => {
const engine = new Engine()
expect(engine.configurable).toBe(true)
engine.createEntity()
expect(engine.configurable).toBe(false)
})

test('removeEntity() should remove the entity', () => {
const engine = new Engine()
engine.started = true
const e1 = engine.createEntity()
const e2 = engine.createEntity()
const e3 = engine.createEntity()
Expand All @@ -55,4 +52,7 @@ describe('Engine', () => {

// TODO: Test registerSystem
// TODO: Test registerComponent
// TODO: Test update
// TODO: Test runSystem
// TODO: Test handleChanges
})
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { Engine } from './engine'
export { component } from './component'
export { Query } from './query'
4 changes: 4 additions & 0 deletions src/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ describe('Query', () => {
engine.registerComponent(ComponentC)
const query = Query.all(ComponentA, ComponentB).bake(engine)

engine.started = true

const entity1 = engine.createEntity()
.add(new ComponentA())
query.onChange(entity1)
Expand All @@ -48,6 +50,8 @@ describe('Query', () => {
const engine = new Engine()
const query = Query.all(ComponentA, ComponentB).bake(engine)

engine.started = true

const entity1 = engine.createEntity()
.add(new ComponentA())
.add(new ComponentB())
Expand Down

0 comments on commit 199d560

Please sign in to comment.