Skip to main content

Entity Manipulation

Create or Destroy at runtime

Objects can be created and destroyed at runtime using the world interface:

import {world} from '@8thwall/ecs'

const eid = world.createEntity()
world.deleteEntity(eid)

Create parent/child relationships

const parent = world.createEntity()
const child = world.createEntity()
world.setParent(child, parent)

world.getParent(child) // parent
world.getParent(parent) // 0 (no parent)

for (const eid of world.getChildren(parent)) {
console.log(eid, 'is a child of', parent)
}

Helper functions

There are a number of helper functions for interacting with entity transforms. We will be addin more over time as needed.

world.setScale(eid, 1, 1, 1)
world.setPosition(eid, 1, 1, 1)
world.setQuaternion(eid, 0, 0, 0, 1)
world.normalizeQuaternion(eid)

const tempMatrix = ecs.math.mat4.i()
world.getWorldTransform(eid1, tempMatrix)

world.setTransform(eid2, tempMatrix)

Entities are positioned relative to their parent. getWorldTransform gets the world transform of the object, taking parent transforms into account.

Register Behavior

A behavior is a function that runs on the world every tick.

ecs.registerBehavior(behavior)

const behavior = (world) => {
if (world.time.elapsed % 5000 - world.time.delta < 0) {
// 5 seconds have passed, spawn a new enemy
const eid = world.createEntity()
Enemy.set(world, eid, {health: 100})
}
}

ecs.registerBehavior(behavior)

Deactivate Behavior

Behaviors can also be deactivated with:

ecs.unregisterBehavior(behavior)

Query Behavior

Behaviors can run queries, which return lists of entity IDs.

const query = ecs.defineQuery([Enemy, Health]) // Query for Enemies that also have Health so we will know that Health.get() will not throw an error

const enemyDieBehavior = (world) => {
const enemies = query(world)

for (const enemyId in enemies) {
if (Health.get(world, enemyId).hp <= 0) {
world.destroyEntity(enemyId)
}
}
}

ecs.registerBehavior(enemyDieBehavior)

note

Depending on how many enemies there are, checking the health of every enemy on every tick might not be the most performant. The above is just an example.

Systems

Behaviors can also be implemented as "systems", which are a way to run a behavior on a query match, with efficient data lookup. To express the same logic from the previous example:

const enemyDieSystem = ecs.defineSystem(
[Enemy, Health],
(world, eid, [enemy, health]) => {
if (health.hp <= 0) {
world.destroyEntity(eid)
}
}
)

ecs.registerBehavior(enemyDieSystem)

The benefit of this approach is performance - the "enemy" and "health" cursors are pre-loaded, so iteration is very fast.