Events
You'll eventually need to detect when components are added, removed, or modified. For example, you may want to know when a component is attached to, or detached from, an entity in order to trigger a change in the ECS or notify a third-party library. You can use some of Javelin's built-in effects and methods to react to these kinds of events.
Monitors#
The best way to detect when an entity matches or no longer matches a query is with a monitor. useMonitor
is an effect that accepts a query and executes callbacks when an entity meets or no longer meets the query's criteria.
useMonitor
accepts onEnter
and onExit
callback functions. An entity is only included in a monitor's results once while it continues to match the query. An entity is eligible again only if it is excluded (i.e. due to a change in its archetype) and re-included.
const spooky = createQuery(Enemy, Ghost)
const controlAi = () => {
useMonitor(
spooky,
entity => {}, // entity matches query `spooky`
entity => {}, // entity no longer matches query `spooky`
)
}
In the above example, the entity passed to the onEnter
callback is an entity who made one of the following type transitions last step:
from | to
--------|----------------
() | (Enemy, Ghost)
(Enemy) | (Enemy, Ghost)
(Ghost) | (Enemy, Ghost)
Below is an example of an entity transitioning between multiple archetypes, and whether or not that transition would result in the entity being passed to the onEnter
callback:
(Enemy) -> excluded
(Enemy, Ghost) -> included
(Enemy, Ghost, Confused) -> excluded
(Ghost, Confused) -> excluded
(Enemy, Ghost) -> included
Component Changes#
The onEnter
and onExit
callbacks are also provided query results as well as a diff containing the components whose changes triggered the monitor.
useMonitor(
bodies,
(entity, [position, velocity], diff) => {
if (diff[0]) {
/* position was attached */
}
},
(entity, [position, velocity], diff) => {
if (diff[0]) {
/* position was detached */
}
},
)