Skip to content

Commit

Permalink
Add 2 different types of systems and helpers to create them. Add JSDo…
Browse files Browse the repository at this point in the history
…c to most of the public api's
  • Loading branch information
sondresj committed Oct 11, 2021
1 parent cc539f7 commit cd53341
Show file tree
Hide file tree
Showing 16 changed files with 326 additions and 160 deletions.
2 changes: 1 addition & 1 deletion packages/piecs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "piecs",
"version": "0.1.1",
"version": "0.2.0",
"description": "PIECS is an entity component system with some batteries included",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
14 changes: 7 additions & 7 deletions packages/piecs/performance/add_remove.mjs
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { World, prefab, query } from '../dist/index.mjs'
import { World, prefab, query, createEntitySystem } from '../dist/index.mjs'

export default function createAddRemove(count) {
const world = new World()
const A = world.getNextComponentId()
const B = world.getNextComponentId()
const A = world.createComponentId()
const B = world.createComponentId()

const prefabA = world.prefabricate([A])
const prefabAB = world.prefabricate([A, B])

world
.registerSystem(function addB(entities, world) {
.registerSystem(createEntitySystem(function addB(entities, world) {
const lpab = prefabAB
for (let i = entities.length - 1; i >= 0; i--) {
// world.addComponentId(entities[i], B)
world.transformEntity(entities[i], lpab)
}
}, query(prefab(prefabA)))
.registerSystem(function removeB(entities, world) {
}, query(prefab(prefabA))))
.registerSystem(createEntitySystem(function removeB(entities, world) {
const lpa = prefabA
for (let i = entities.length - 1; i >= 0; i--) {
// world.removeComponentId(entities[i], B)
world.transformEntity(entities[i], lpa)
}
}, query(prefab(prefabAB)))
}, query(prefab(prefabAB))))
.initialize()

for (let i = 0; i < count; i++) {
Expand Down
14 changes: 7 additions & 7 deletions packages/piecs/performance/entity_cycle.mjs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { World, prefab, query } from '../dist/index.mjs'
import { World, prefab, query, createEntitySystem } from '../dist/index.mjs'

export default function createEntityCycle(count) {
const world = new World()
const A = world.getNextComponentId()
const B = world.getNextComponentId()
const A = world.createComponentId()
const B = world.createComponentId()

const prefabA = world.prefabricate([A])
const prefabB = world.prefabricate([B])

world
.registerSystem(function spawnBs(entities, world) {
.registerSystem(createEntitySystem(function spawnBs(entities, world) {
const lpb = prefabB
for (let i = 0, l = entities.length; i < l; i++) {
world.transformEntity(world.createEntity(), lpb)
world.transformEntity(world.createEntity(), lpb)
}
}, query(prefab(prefabA)))
.registerSystem(function deleteBs(entities, world) {
}, query(prefab(prefabA))))
.registerSystem(createEntitySystem(function deleteBs(entities, world) {
for (let i = entities.length - 1; i >= 0; i--) {
world.deleteEntity(entities[i])
}
}, query(prefab(prefabB)))
}, query(prefab(prefabB))))
.initialize()

for (let i = 0; i < count; i++) {
Expand Down
10 changes: 5 additions & 5 deletions packages/piecs/performance/frag_iter.mjs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { World, all, query } from '../dist/index.mjs'
import { World, all, query, createEntitySystem } from '../dist/index.mjs'

export default function createFragIter(count) {
const world = new World()

const components = []
for (let i = 0; i < 26; i++) {
components.push(world.getNextComponentId())
components.push(world.createComponentId())
}
const Data = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count*26).fill(1)
}

const prefabs = components.map(c => world.prefabricate([Data.id, c]))

world
.registerSystem(function dataSystem(entities) {
.registerSystem(createEntitySystem(function dataSystem(entities) {
const DataArray = Data.arr
for (let i = 0, l = entities.length; i < l; i++) {
DataArray[entities[i]] *= 2
}
}, query(all(Data.id)))
}, query(all(Data.id))))
.initialize()

for (let i = 0; i < count; i++) {
Expand Down
16 changes: 8 additions & 8 deletions packages/piecs/performance/packed_1.mjs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { World, prefab, query } from '../dist/index.mjs'
import { World, prefab, query, createEntitySystem } from '../dist/index.mjs'

export default function createPacked1(count) {
const world = new World()
const A = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count).fill(0)
}
const B = world.getNextComponentId()
const C = world.getNextComponentId()
const D = world.getNextComponentId()
const E = world.getNextComponentId()
const B = world.createComponentId()
const C = world.createComponentId()
const D = world.createComponentId()
const E = world.createComponentId()

const p = world.prefabricate([A.id, B, C, D, E])

world
.registerSystem(function systemAp1(entities) {
.registerSystem(createEntitySystem(function systemAp1(entities) {
const AArray = A.arr
for (let i = 0, l = entities.length; i < l; i++) {
AArray[entities[i]] *= 2
}
}, query(prefab(p)))
}, query(prefab(p))))
.initialize()

for (let i = 0; i < count; i++) {
Expand Down
32 changes: 16 additions & 16 deletions packages/piecs/performance/packed_5.mjs
Original file line number Diff line number Diff line change
@@ -1,62 +1,62 @@
import { World, prefab, query } from '../dist/index.mjs'
import { World, prefab, query, createEntitySystem } from '../dist/index.mjs'

export default function createPacked5(count) {
const world = new World()

const A = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count).fill(1)
}
const B = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count).fill(1)
}
const C = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count).fill(1)
}
const D = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count).fill(1)
}
const E = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count).fill(1)
}

const p = world.prefabricate([A.id, B.id, C.id, D.id, E.id])

world
.registerSystem(function systemAp5(entities) {
.registerSystem(createEntitySystem(function systemAp5(entities) {
const arr = A.arr
for (let i = 0, l = entities.length; i < l; i++) {
arr[entities[i]] *= 2
}
}, query(prefab(p)))
.registerSystem(function systemBp5(entities) {
}, query(prefab(p))))
.registerSystem(createEntitySystem(function systemBp5(entities) {
const arr = B.arr
for (let i = 0, l = entities.length; i < l; i++) {
arr[entities[i]] *= 2
}
}, query(prefab(p)))
.registerSystem(function systemCp5(entities) {
}, query(prefab(p))))
.registerSystem(createEntitySystem(function systemCp5(entities) {
const arr = C.arr
for (let i = 0, l = entities.length; i < l; i++) {
arr[entities[i]] *= 2
}
}, query(prefab(p)))
.registerSystem(function systemDp5(entities) {
}, query(prefab(p))))
.registerSystem(createEntitySystem(function systemDp5(entities) {
const arr = D.arr
for (let i = 0, l = entities.length; i < l; i++) {
arr[entities[i]] *= 2
}
}, query(prefab(p)))
.registerSystem(function systemEp5(entities) {
}, query(prefab(p))))
.registerSystem(createEntitySystem(function systemEp5(entities) {
const arr = E.arr
for (let i = 0, l = entities.length; i < l; i++) {
arr[entities[i]] *= 2
}
}, query(prefab(p)))
}, query(prefab(p))))
.initialize()

for (let i = 0; i < count; i++) {
Expand Down
24 changes: 12 additions & 12 deletions packages/piecs/performance/simple_iter.mjs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { World, prefab, query } from '../dist/index.mjs'
import { World, prefab, query, createEntitySystem } from '../dist/index.mjs'

export default function createSimpleIter(count) {
const world = new World()
const A = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count*4).fill(0)
}
const B = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count*4).fill(0)
}
const C = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count*4).fill(0)
}
const D = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count*4).fill(0)
}
const E = {
id: world.getNextComponentId(),
id: world.createComponentId(),
arr: new Uint32Array(count*4).fill(0)
}

Expand All @@ -29,7 +29,7 @@ export default function createSimpleIter(count) {
const prefab4 = world.prefabricate([A.id, B.id, C.id, E.id])

world
.registerSystem(function systemAB(entities) {
.registerSystem(createEntitySystem(function systemAB(entities) {
const lA = A.arr
const lB = B.arr
for (let i = 0, l = entities.length; i < l; i++) {
Expand All @@ -39,8 +39,8 @@ export default function createSimpleIter(count) {
lA[entity] = b
lB[entity] = a
}
}, query(prefab(prefab1)))
.registerSystem(function systemCD(entities) {
}, query(prefab(prefab1))))
.registerSystem(createEntitySystem(function systemCD(entities) {
const lC = C.arr
const lD = D.arr
for (let i = 0, l = entities.length; i < l; i++) {
Expand All @@ -50,8 +50,8 @@ export default function createSimpleIter(count) {
lC[entity] = d
lD[entity] = c
}
}, query(prefab(prefab3)))
.registerSystem(function systemCE(entities) {
}, query(prefab(prefab3))))
.registerSystem(createEntitySystem(function systemCE(entities) {
const lC = C.arr
const lE = E.arr
for (let i = 0, l = entities.length; i < l; i++) {
Expand All @@ -61,7 +61,7 @@ export default function createSimpleIter(count) {
lC[entity] = e
lE[entity] = c
}
}, query(prefab(prefab4)))
}, query(prefab(prefab4))))
.initialize()

for (let i = 0; i < count; i++) {
Expand Down
49 changes: 41 additions & 8 deletions packages/piecs/src/Archetype.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,65 @@
import type { ReadonlyBitSet } from './collections/BitSet'
import { createSparseSet, SparseSet } from './collections/SparseSet'

export type InternalArchetype = {
export type Archetype = {
/**
* The id of the archetype is a hexadecimal representation of a set of unique bits for all of the `componentIds`
*/
readonly id: string
/**
* All the `componentIds` constituting this archetype
*/
readonly componentIds: ReadonlyArray<number>
/**
* Check if an entity is currently included in this archetype
*/
hasEntity: (entity: number) => boolean
/**
* Check if this archetype has a `componentId`.
* This is typically much faster than checking if `componentIds` includes a given componentId
*/
hasComponentId: (componentId: number) => boolean
/**
* Returns all the entities currently in this archetype
*/
getEntities(): ArrayLike<number>
}

export type InternalArchetype = Archetype & {
readonly mask: ReadonlyBitSet
readonly entitySet: SparseSet
readonly adjacent: InternalArchetype[]
readonly parent: InternalArchetype | null
readonly componentIds: number[]
}

export type Archetype = {
readonly id: string
readonly componentIds: ReadonlyArray<number>
}

export function createArchetype(id: string, mask: ReadonlyBitSet, parent: InternalArchetype | null): InternalArchetype {
const entitySet = createSparseSet()
const adjacent: InternalArchetype[] = []
const componentIds: number[] = []

function hasEntity(entity: number): boolean {
return entitySet.has(entity)
}

function hasComponentId(componentId: number): boolean {
return mask.has(componentId)
}

function getEntities(): ArrayLike<number> {
return entitySet.values
}

return Object.freeze({
id,
mask,
entitySet,
adjacent,
parent,
componentIds
componentIds,
hasEntity,
hasComponentId,
getEntities
})
}

Expand Down Expand Up @@ -55,7 +88,7 @@ export function transformArchetype(archetype: InternalArchetype, componentId: nu
transformed.adjacent[componentId] = archetype
archetype.adjacent[componentId] = transformed
if (!existingArchetype)
transformed.componentIds.push(componentId)
transformed.componentIds.push(...archetype.componentIds, componentId)
return transformed
}

Expand Down
11 changes: 0 additions & 11 deletions packages/piecs/src/Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,3 @@ export class WorldNotInitializedError extends Error {
super('World not initialized')
}
}

export class PrefabricationError extends Error {
constructor(componentIds: number[], nextComponentId: number) {
super(`
Cannot prefabricate using componentIds that would conflict with existing componentIds.
Make sure you either prefabricate before generating componentIds with world.getNextComponentId(),
or prefabricate using componentIds generated by world.getNextComponentId().
Conflicting componentIds: [${componentIds.filter(id => id < nextComponentId).join(', ')}]
`)
}
}
Loading

0 comments on commit cd53341

Please sign in to comment.