Events
Introduction
Events are how entities can communicate with each other through a flexible listener and dispatch system.Event Listeners
Listener
Property | Type | Description |
---|---|---|
target | eid | Entity the event was dispatched on. |
currentTarget | eid | Entity the event was listened on. |
name | string | Name of the event. |
data | any | Event custom data |
Creating Event Listeners
addListener
world.events.addListener(target, name, listener)
Parameters
It's possible to create global event listeners by using world.events.globalId
as the target.
Property | Type | Description |
---|---|---|
target | eid | Reference to the target entity. |
name | string | Name of the event to listen for. |
listener | Listener | The callback function for when an event is triggered |
Creating Event Handlers
When adding event listeners to entities, it’s crucial to set up handlers correctly to ensure they function as intended, especially when components are added to multiple entities. Improper handler creation can lead to stale references and unexpected behavior.
Suppose you’re creating a handler for an NPC entity that listens for a damaged event. The handler should update some schema and data values when the event occurs.
Incorrect Example
import * as ecs from '@8thwall/ecs'
import { addCleanup, doCleanup } from './cleanup'
ecs.registerComponent({
name: 'npc',
schema: {
isInjured: ecs.boolean,
},
data: {
bpm: ecs.f32,
},
add: (world, component) => {
// Incorrect handler creation
const damagedHandler = (e) => {
component.schema.isInjured = true
component.data.bpm += 30
}
world.events.addListener(component.eid, 'damaged', damagedHandler)
const cleanup = () => {
world.events.removeListener(component.eid, 'damaged', damagedHandler)
}
addCleanup(component, cleanup)
},
remove: (world, component) => {
doCleanup(component)
},
})
In this example:
- The handler damagedHandler directly references
component.schema
andcomponent.data
. - If the component is added to multiple entities, the component reference inside the handler becomes stale.
- This can cause the handler to operate on incorrect data, leading to bugs.
Correct Example
To ensure the handler operates on the correct entity data, pass the component’s dataAttribute
and schemaAttribute
to the handler and use them to fetch cursors inside the handler.
import * as ecs from '@8thwall/ecs'
import { addCleanup, doCleanup } from './cleanup'
// Function to create the damaged handler
const createDamagedHandler = (dataAttribute, schemaAttribute) => (e) => {
const dataCursor = dataAttribute.cursor(e.target)
const schemaCursor = schemaAttribute.cursor(e.target)
schemaCursor.isInjured = true
dataCursor.bpm += 30
}
ecs.registerComponent({
name: 'npc',
schema: {
isInjured: ecs.boolean,
},
data: {
bpm: ecs.f32,
},
add: (world, component) => {
// Correct handler creation
const damagedHandler = createDamagedHandler(component.dataAttribute, component.schemaAttribute)
world.events.addListener(component.eid, 'damaged', damagedHandler)
const cleanup = () => {
world.events.removeListener(component.eid, 'damaged', damagedHandler)
}
addCleanup(component, cleanup)
},
remove: (world, component) => {
doCleanup(component)
},
})
Removing Event Listeners
removeListener
world.events.removeListener(target, name, listener)
Parameters
Property | Type | Description |
---|---|---|
target | eid | Reference to the target entity. |
name | string | Name of the event to listen for. |
listener | Listener | The callback function for when an event is triggered |
Event Dispatchers
Dispatching Custom Events
Dispatch
When an event happens on an entity, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.
world.events.dispatch(eidOfEnemy, "attack", {damage: 10})
Cleaning Up Listeners
Always ensure listeners are properly removed to avoid memory leaks.
When a component is deleted, its event listeners are not automatically cleaned up, so you must remove them manually.