Skip to content
Flecs v4.1
observers/basics

  • C

    View on GitHub

    1#include <basics.h>
    2#include <stdio.h>
    3
    4// Observers provide a mechanism for responding to builtin and user defined
    5// events. They are similar to systems, in that they have the same callback
    6// signature and use the same query interface to match with entities, but
    7// instead of a phase they have an event kind.
    8//
    9// The most commonly used builtin events are:
    10// - EcsOnAdd: a component was added
    11// - EcsOnRemove: a component was removed
    12// - EcsOnSet: a component's value was changed
    13//
    14// The EcsOnAdd and EcsOnRemove events are only thrown when a component is
    15// actually added or removed. If an application invokes ecs_add and the entity
    16// already has the component, no event is emitted. Similarly, if an application
    17// invokes ecs_remove for a component the entity doesn't have, no event is
    18// emitted. That is in contrast to EcsOnSet, which is invoked each time ecs_set
    19// or ecs_modified is invoked.
    20//
    21// Observers are different from component hooks in a number of ways:
    22// - A component can only have one hook, whereas it can match many observers
    23// - A hook matches one component, whereas observers can match complex queries
    24// - Hooks are for add/set/remove events, observers can match custom events.
    25
    26typedef struct {
    27 double x, y;
    28} Position;
    29
    30void Observer(ecs_iter_t *it) {
    31 ecs_world_t *ecs = it->stage;
    32
    33 // The event kind
    34 ecs_entity_t event = it->event;
    35
    36 // The (component) id for which the event was emitted
    37 ecs_entity_t event_id = it->event_id;
    38
    39 // Get component values as usual
    40 Position *p = ecs_field(it, Position, 0);
    41
    42 for (int i = 0; i < it->count; i ++) {
    43 ecs_entity_t e = it->entities[i];
    44
    45 if (event == EcsOnAdd) {
    46 // No assumptions about the component value should be made here. If
    47 // a ctor for the component was registered it will be called before
    48 // the EcsOnAdd event, but a value assigned by set won't be visible.
    49 printf(" - OnAdd: %s: %s\n",
    50 ecs_get_name(ecs, event_id),
    51 ecs_get_name(ecs, e));
    52 } else {
    53 // EcsOnSet or EcsOnRemove event
    54 printf(" - %s: %s: %s: {%f, %f}\n",
    55 ecs_get_name(ecs, event),
    56 ecs_get_name(ecs, event_id),
    57 ecs_get_name(ecs, e),
    58 p[i].x, p[i].y);
    59 }
    60 }
    61}
    62
    63int main(int argc, char *argv[]) {
    64 ecs_world_t *ecs = ecs_init_w_args(argc, argv);
    65
    66 ECS_COMPONENT(ecs, Position);
    67
    68 // The ecs_observer macro (which calls the ecs_observer_init function) can
    69 // be used to create an observer.
    70 ecs_observer(ecs, {
    71 // Observer query. Uses same ecs_query_desc_t as systems/queries
    72 .query = { .terms = {{ .id = ecs_id(Position) }}},
    73 // Events the observer will listen for. Can contain multiple events
    74 .events = { EcsOnAdd, EcsOnRemove },
    75 // Observer callback
    76 .callback = Observer
    77 });
    78
    79 // Alternatively an observer can be created with the ECS_OBSERVER macro:
    80 ECS_OBSERVER(ecs, Observer, EcsOnSet, Position);
    81
    82 // Create entity
    83 ecs_entity_t e = ecs_entity(ecs, { .name = "e" });
    84
    85 // Set Position (emits EcsOnAdd and EcsOnSet)
    86 ecs_set(ecs, e, Position, {10, 20});
    87
    88 // Remove component (emits EcsOnRemove)
    89 ecs_remove(ecs, e, Position);
    90
    91 // Remove component again (no event is emitted)
    92 ecs_remove(ecs, e, Position);
    93
    94 ecs_fini(ecs);
    95
    96 // Output
    97 // - OnAdd: Position: e
    98 // - OnSet: Position: e: {10.000000, 20.000000}
    99 // - OnRemove: Position: e: {10.000000, 20.000000}
    100}
    const ecs_entity_t EcsOnRemove
    Event that triggers when an ID is removed from an entity.
    const ecs_entity_t EcsOnSet
    Event that triggers when a component is set for an entity.
    const ecs_entity_t EcsOnAdd
    Event that triggers when an ID is added to an entity.
    FLECS_API const ecs_entity_t ecs_id(EcsDocDescription)
    Component ID for EcsDocDescription.
    ecs_id_t ecs_entity_t
    An entity identifier.
    Definition flecs.h:395
    struct ecs_world_t ecs_world_t
    A world is the container for all ECS data and supporting features.
    Definition flecs.h:439
    #define ecs_remove(world, entity, T)
    Remove a component from an entity.
    Definition flecs_c.h:279
    #define ecs_entity(world,...)
    Shorthand for creating an entity with ecs_entity_init().
    Definition flecs_c.h:188
    #define ECS_OBSERVER(world, id, kind,...)
    Declare and define an observer.
    Definition flecs_c.h:136
    #define ecs_observer(world,...)
    Shorthand for creating an observer with ecs_observer_init().
    Definition flecs_c.h:230
    #define ECS_COMPONENT(world, id)
    Declare and define a component.
    Definition flecs_c.h:98
    #define ecs_set(world, entity, component,...)
    Set a component value.
    Definition flecs_c.h:310
    #define ecs_field(it, T, index)
    Get field data for a component.
    Definition flecs_c.h:720
    const char * ecs_get_name(const ecs_world_t *world, ecs_entity_t entity)
    Get the name of an entity.
    int ecs_fini(ecs_world_t *world)
    Delete a world.
    ecs_world_t * ecs_init_w_args(int argc, char *argv[])
    Create a new world with arguments.
    Iterator.
    Definition flecs.h:1183
    ecs_entity_t event
    The event (if applicable).
    Definition flecs.h:1209
    ecs_id_t event_id
    The (component) ID for the event.
    Definition flecs.h:1210
    int32_t count
    Number of entities to iterate.
    Definition flecs.h:1189
    const ecs_entity_t * entities
    Entity identifiers.
    Definition flecs.h:1190

  • C++

    View on GitHub

    1#include <basics.h>
    2#include <iostream>
    3
    4// Observers provide a mechanism for responding to builtin and user defined
    5// events. They are similar to systems, in that they have the same callback
    6// signature and use the same query interface to match with entities, but
    7// instead of a phase they have an event kind.
    8//
    9// The most commonly used builtin events are:
    10// - flecs::OnAdd: a component was added
    11// - flecs::OnRemove: a component was removed
    12// - flecs::OnSet: a component's value was changed
    13//
    14// The OnAdd and OnRemove events are only thrown when a component is
    15// actually added or removed. If an application invokes add and the entity
    16// already has the component, no event is emitted. Similarly, if an application
    17// invokes remove for a component the entity doesn't have, no event is
    18// emitted. That is in contrast to OnSet, which is invoked each time set
    19// or modified is invoked.
    20//
    21// Observers are different from component hooks in a number of ways:
    22// - A component can only have one hook, whereas it can match many observers
    23// - A hook matches one component, whereas observers can match complex queries
    24// - Hooks are for add/set/remove events, observers can match custom events.
    25
    26struct Position {
    27 double x, y;
    28};
    29
    30int main(int, char *[]) {
    31 flecs::world ecs;
    32
    33 // Create an observer for three events
    34 ecs.observer<Position>()
    35 .event(flecs::OnAdd)
    36 .event(flecs::OnRemove)
    37 .event(flecs::OnSet)
    38 .each([](flecs::iter& it, size_t i, Position& p) {
    39 if (it.event() == flecs::OnAdd) {
    40 // No assumptions about the component value should be made here. If
    41 // a ctor for the component was registered it will be called before
    42 // the EcsOnAdd event, but a value assigned by set won't be visible.
    43 std::cout << " - OnAdd: " << it.event_id().str() << ": "
    44 << it.entity(i).name() << "\n";
    45 } else {
    46 // EcsOnSet or EcsOnRemove event
    47 std::cout << " - " << it.event().name() << ": "
    48 << it.event_id().str() << ": "
    49 << it.entity(i).name()
    50 << ": {" << p.x << ", " << p.y << "}\n";
    51 }
    52 });
    53
    54 // Create entity, set Position (emits EcsOnAdd and EcsOnSet)
    55 flecs::entity e = ecs.entity("e")
    56 .set<Position>({10, 20});
    57
    58 // Remove component (emits EcsOnRemove)
    59 e.remove<Position>();
    60
    61 // Remove component again (no event is emitted)
    62 e.remove<Position>();
    63
    64 // Output
    65 // - OnAdd: Position: e
    66 // - OnSet: Position: e: {10, 20}
    67 // - OnRemove: Position: e: {10, 20}
    68}
    flecs::entity entity(Args &&... args) const
    Create an entity.
    Definition impl.hpp:195
    flecs::observer observer(flecs::entity e) const
    Observer world mixin.
    Definition impl.hpp:85
    flecs::string_view name() const
    Return the entity name.
    Entity.
    Definition entity.hpp:30
    flecs::string str() const
    Convert ID to string.
    Definition decl.hpp:128
    Class for iterating over query results.
    Definition iter.hpp:68
    flecs::entity event() const
    Get the event entity associated with the iterator.
    Definition iter.hpp:17
    flecs::entity entity(size_t row) const
    Obtain a mutable handle to the entity being iterated over.
    Definition iter.hpp:36
    flecs::id event_id() const
    Get the event ID associated with the iterator.
    Definition iter.hpp:22
    The world.
    Definition world.hpp:129