Skip to content

Commit 449c1b3

Browse files
events and dependencies
1 parent 126080c commit 449c1b3

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

examples/snake/src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ if (canvas && canvas instanceof HTMLCanvasElement) {
6767
}
6868
);
6969

70-
renderer(world.update);
70+
renderer((deltaTime) => world.update(deltaTime));
7171
} else {
7272
console.error("Canvas context not found");
7373
}

packages/core/README.md

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ The library does nothing more than organizing the logic of your game into entity
121121

122122
The created `ECS` instance provides an `update` function that you can call each frame to update the game, using whatever other library or framework you prefer:
123123

124-
> Calling `update` will execute all the systems in the world one time. You are expected to call `update` once per frame (or whatever other frequency you prefer).
124+
> Calling `update` will execute all the systems in the world **one time**. You are expected to call `update` once per frame (or whatever other frequency you prefer).
125125
126126
```ts
127127
// Create a world for a snake game (add systems, create entities, etc.)
@@ -163,9 +163,72 @@ const world = ECS.create<SystemTags, GameEventMap>(
163163
);
164164

165165
// Apply any rendering logic by executing the `update` function from `ECS`
166-
renderer(world.update);
166+
renderer((deltaTime) => world.update(deltaTime));
167167
```
168168

169+
### Communication between systems
170+
Events are used to send messages between systems. Any system has access to the `emit` function to emit events:
171+
172+
> Events are type-safe and must be defined in the `GameEventMap` type.
173+
174+
```ts
175+
export const FoodEatenEvent = Symbol("FoodEaten");
176+
177+
export interface GameEventMap extends EventMap {
178+
[FoodEatenEvent]: { entityId: EntityId };
179+
}
180+
```
181+
182+
You can then emit an event using the `emit` function:
183+
184+
```ts
185+
export class CollisionSystem extends SystemFactory<{}>("Collision", {
186+
execute: ({ emit }) => {
187+
if (/* collision detected */) {
188+
emit({
189+
type: FoodEatenEvent, // 👈 Emit the event from its unique symbol
190+
data: { entityId: entity.entityId }, // 👈 Pass the entity that was eaten
191+
});
192+
}
193+
},
194+
}) {}
195+
```
196+
197+
Other systems can use the `poll` function to extract events and react to them:
198+
199+
> Important: events are **cleaned up after each update cycle**. If you want to ensure an event was emitted before executing a system you can use `dependencies` (see below).
200+
201+
```ts
202+
export class SnakeGrowSystem extends SystemFactory<{}>("SnakeGrow", {
203+
dependencies: ["Collision"], // 👈 Ensure the `Collision` system has been executed and events collected
204+
execute: ({ poll }) => {
205+
poll(FoodEatenEvent).forEach(({ entityId }) => {
206+
// Do something with the event (`entityId`)
207+
});
208+
},
209+
}) {}
210+
```
211+
212+
### Systems dependencies
213+
Sometimes you need to execute a system after another system.
214+
215+
For example, you might want to spawn food only after the snake has eaten it. This creates a dependency between the `FoodSpawnSystem` and the `CollisionSystem`: you first want to detect collisions, and then spawn food if a collision occurs.
216+
217+
You can define a dependency between two systems using the *optional* `dependencies` property:
218+
219+
```ts
220+
export class FoodSpawnSystem extends SystemFactory<{}>("FoodSpawn", {
221+
// Execute this system after the `Collision` system
222+
dependencies: ["Collision"],
223+
224+
execute: ({ world }) => {
225+
// Inside here all collisions are already detected from the `CollisionSystem`
226+
},
227+
}) {}
228+
```
229+
230+
You can specify multiple dependencies. The library takes care of resolving each system's dependencies and execute them in the correct order.
231+
169232
***
170233

171234
## API

0 commit comments

Comments
 (0)