You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/learn/book/control-flow/events.md
+54-12Lines changed: 54 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,13 +8,13 @@ status = 'hidden'
8
8
9
9
<!-- TBW -->
10
10
11
-
While Systems are great for running logic at scheduled updates, many features need to be reactive, not scheduled. Picking up an item, performing an attack, or even hovering the mouse over an object are all actions that wouldn't work very well if they *had* to run on every schedule update. Instead of a System, we can use **Events** to activate some logic or functionality at a specific time or in response to something occurring.
11
+
While Systems are great for running logic at scheduled updates, many features need to be reactive, not scheduled. Picking up an item, performing an attack, or even hovering the cursor over an object are all actions that wouldn't work very well if they *had* to run on every schedule update. Instead of a System, we can use **Events** to activate some logic or functionality at a specific time or in response to something occurring.
12
12
13
13
There are three required parts when using an Event: a **Trigger**, an **Observer**, and the `Event` itself.
14
14
15
15
- A **Trigger** is the condition that will determine when an `Event` will happen in the `World`.
16
16
- The Entities that will react to our `Event` are known as **Observers**. These Entities "observe" the `World` and will run some functionality in response to our `Event`.
17
-
- Finally, the `Event` is a Rust type that implements the `Event` trait.
17
+
- Finally, the `Event` is a Rust type that implements the [`Event`] trait.
18
18
19
19
A basic use of an `Event` would something like this:
20
20
@@ -27,7 +27,7 @@ struct Speak {
27
27
}
28
28
```
29
29
30
-
2. Add an [`Observer`] to the World that will watch for our event:
30
+
2. Add an [`Observer`] to the `World` that will watch for our event:
Once we have defined our `Event`, we need to create an [`Observer`] that will do something when our `Event` gets triggered. This can be as straightforward as calling the `add_observer` method on [`World`] or [`Commands`], but this is not the only way to make an `Observer`.
85
+
86
+
At its core, `Observer` is a [`Component`] that is added to an `Entity`. When we run `World::add_observer`, all that's actually happening is telling `World` to spawn a new `Entity` with an `Observer` component. Within that `Observer` component, we specify what `Event` we want the `Entity` to react to and what should happen when the `Event` happens. As we'll see later on with `EntityEvent`, this can be very handy for when we have an `Observer` that should only run when targeting a *specific*`Entity`.
87
+
88
+
```rust
89
+
// `world` creates a new `Entity` with an `Observer` component, watching for a `Speak` event.
90
+
world.add_observer(|speak:On<Speak>| {
91
+
// When `Speak` is triggered, print out the message to the console.
92
+
println!("{}", speak.message);
93
+
});
94
+
```
95
+
96
+
### Observer Systems
97
+
98
+
As you've seen by now, an `Observer` will run some functionality when the `Event` it is observing is triggered. We're able to do this because `Observer` has the ability to run a special kind of `System` called an `ObserverSystem`. The first parameter in an `ObserverSystem` must be `On`, which provides access to the observed `Event`, however we are also able to access more data from `World`.
In the above example, we've created an `Observer` that will run its `ObserverSystem` when a `DespawnEnemyUnits` event is triggered. Additionally, we've accessed `Commands` and `Query` as parameters to gain access to the data we need. Within the `ObserverSystem`, we use a `for` loop to despawn every `Enemy` entity that is given in the `enemy_units` query.
109
+
110
+
It is also worth noting that we can trigger an `Event` within an `ObserverSystem`. Instead of triggering immediately (as is the case when using `World::trigger`), triggering an `Event` inside an `Observer` with `Commands::trigger` will run the newly triggered `ObserverSystem` at the end of the `Command` queue. Once all of the other `Observer` commands that are currently in the queue are ran, then the new `ObserverSystem` will be run. Be aware that these events are evaluated *recursively*, and will exit once there are no more events left.
111
+
112
+
```rust
113
+
// When Event `A` is triggered, it in turn will trigger Event `B`.
Every `Event` requires a [`Trigger`], represented by default with the `On<Event>` syntax. It's best to think of a `Trigger` as the call which activates the `Event`, hence why we use `On`: our code will run `On` our `<Event>`.
85
124
86
-
A [`Trigger`] can be called by accessing [`World`] (via [`World::trigger`]) to run the `Event` immediately, or by using [`Commands`] (via [`Commands::trigger`]) to add the `Event` to the Command Queue.
125
+
A [`Trigger`] can be called by accessing `World` (via [`World::trigger`]) to run the `Event` immediately, or by using `Commands` (via [`Commands::trigger`]) to add the `Event` to the `Command` Queue.
87
126
88
127
```rust
89
128
// An event that deals damage to the player.
@@ -131,7 +170,7 @@ As we mentioned above, a `Trigger` can also be used to pass values from the `Eve
131
170
132
171
## Entity Events
133
172
134
-
Up until now, Events have been utilized in a *global* context, meaning that observers will run their code without taking any specific entities into account.
173
+
Up until now, events have been utilized in a *global* context, meaning that observers will run their code without taking any specific entities into account.
135
174
136
175
What if we do have some unique functionality that we want to run on certain entities? We can achieve this by modifying our `Event` types to implement [`EntityEvent`] rather than [`Event`]:
137
176
@@ -149,7 +188,7 @@ struct Explode {
149
188
}
150
189
```
151
190
152
-
With [`EntityEvent`], we are selecting a single `Entity` that will respond to our event. To determine the selected `Entity`, we need to provide the `EventEntity` with an `entity_target` field. By default, `event_target` will be set to the value inside an `entity` field in a struct (if it exists). Otherwise we can manually specify the `event_target` by using the `#[event_target]` field attribute.
191
+
With [`EntityEvent`], we are selecting a single `Entity` that will be the target of our event. To determine the selected `Entity`, we need to provide the `EventEntity` with an `entity_target` field. By default, `event_target` will be set to the value inside an `entity` field in a struct (if it exists). Otherwise we can manually specify the `event_target` by using the `#[event_target]` field attribute.
Just as with a global [`Event`], [`EntityEvent`] also needs a [`Trigger`]. Thankfully, we trigger an `EntityEvent` the same way we trigger a regular [`Event`]:
219
+
Just as with a global [`Event`], [`EntityEvent`] also needs a [`Trigger`]. We trigger an `EntityEvent` the same way we trigger a regular `Event`, however this time we make sure to specify our `event_target` entity (along with any other fields on the `EntityEvent`):
181
220
182
221
```rust
183
-
world.trigger(Explode(some_entity, 4, 2.5));
184
222
// Trigger an Explode `EntityEvent`, passing in a tuple consisting of
185
223
// an Entity (`some_entity`), an i32 (`4`), and a f32 (`2.5`).
224
+
world.trigger(Explode(some_entity, 4, 2.5));
186
225
```
187
226
188
-
However, [`EntityEvent`] does differ from [`Event`] when it comes to using an observer. To make an Entity observe an [`EntityEvent`], we have to select the `Entity` with [`World::entity_mut`] and then add the observer with[`EntityCommands::observe`]:
227
+
However, [`EntityEvent`] does differ from [`Event`] when it comes to using an observer. To create an `Observer` for an `EntityEvent`, we have to select the target `Entity` with [`World::entity_mut`] and then create the `Observer` via[`EntityCommands::observe`]:
189
228
190
229
```rust
191
-
/// This observer will only run for Explode events triggered for `some_entity`
230
+
// This observer will only run for Explode events triggered for `some_entity`
0 commit comments