Open-Source Wikis

/

Bevy

/

Primitives

/

Observer

bevyengine/bevy

Observer

An observer is a function that runs in response to an ECS event. Observers are how Bevy implements reactive component lifecycle handling and custom event dispatch in a way that interoperates with the schedule.

The shape

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(MinimalPlugins)
        .add_observer(|trigger: Trigger<OnAdd, Player>, mut commands: Commands| {
            println!("Player {:?} spawned", trigger.target());
            commands.entity(trigger.target()).insert(Health(100));
        })
        .run();
}

Trigger<E, B> is the system parameter. E is the event type; B is the bundle the event applies to (often a single component).

Built-in events

Event Fires when
OnAdd A component is added to an entity.
OnInsert A component is added or replaced.
OnRemove A component is removed.
OnReplace A component is replaced (re-inserted).
OnDespawn An entity is despawned (fires for each component before removal).

These are defined in crates/bevy_ecs/src/lifecycle.rs.

Custom events

#[derive(Event)]
struct DamageDealt { amount: u32 }

world.observe(|trigger: Trigger<DamageDealt>| {
    println!("hit for {}", trigger.event().amount);
});

world.trigger(DamageDealt { amount: 10 });

Observers are scoped to the world they're registered against. They can also be registered per-entity:

commands.spawn(Health(100)).observe(|trigger: Trigger<DamageDealt>, mut health: Query<&mut Health>| {
    if let Ok(mut h) = health.get_mut(trigger.target()) {
        h.0 = h.0.saturating_sub(trigger.event().amount);
    }
});

When a per-entity observer fires, only that entity's handlers receive the event.

Bubbling

Events can propagate up the entity hierarchy via the Traversal trait. The picking events (Pointer<Click>, Pointer<Drag>, …) use this so a click on a deeply-nested UI node can be handled by a parent.

Observers vs systems

Use When
System Runs every frame. Good for "all entities matching X get processed."
Observer Runs in response to a specific event. Good for "when X happens, do Y."

Observers are deferred — they don't run inline at the trigger site. Their effects appear at the next sync point. For inline reactions, use hooks on a component (fn on_add(...)).

Performance

Observers are lighter than the older EventReader/EventWriter pattern when only a handful of entities care, because there's no per-frame scan of an event queue. They are heavier when many entities care, because each handler runs separately. As a rule of thumb: use observers when reaction is rare; use EventReader for high-frequency events.

See also

  • Component — most observers fire on component lifecycle.
  • System — the alternative.
  • bevy_ecscrates/bevy_ecs/src/observer/.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Observer – Bevy wiki | Factory