Skip to content
Flecs v4.1
queries/group_by_callbacks

  • C

    View on GitHub

    1#include <group_by_callbacks.h>
    2#include <stdio.h>
    3#include <stdlib.h>
    4
    5// This example shows how the on_group_create and on_group_delete callbacks can
    6// be used to get notified when a new group is registered for a query. These
    7// callbacks make it possible to associate and manage user data attached to
    8// groups.
    9
    10typedef struct {
    11 double x, y;
    12} Position;
    13
    14// Custom type to associate with group
    15typedef struct {
    16 int32_t counter;
    17} group_ctx;
    18
    19int group_counter = 0;
    20
    21// Callback invoked when a new group is created
    22static void* on_group_create(ecs_world_t *world,
    23 uint64_t group_id, // id of the group that was created
    24 void *group_by_arg) // group_by_ctx parameter in ecs_query_desc_t struct
    25{
    26 (void)group_by_arg; // silence unused warning
    27 printf("Group %s created\n", ecs_get_name(world, group_id));
    28
    29 // Return data that will be associated with the group
    30 group_ctx *ctx = malloc(sizeof(group_ctx));
    31 ctx->counter = ++ group_counter;
    32 return ctx;
    33}
    34
    35// Callback invoked when a group is deleted
    36static void on_group_delete(ecs_world_t *world,
    37 uint64_t group_id, // id of the group that was deleted
    38 void *ctx, // group context
    39 void *group_by_arg) // group_by_ctx parameter in ecs_query_desc_t struct
    40{
    41 (void)group_by_arg; // silence unused warning
    42 printf("Group %s deleted\n", ecs_get_name(world, group_id));
    43
    44 // Free data associated with group
    45 free(ctx);
    46}
    47
    48int main(int argc, char *argv[]) {
    49 ecs_world_t *ecs = ecs_init_w_args(argc, argv);
    50
    51 ECS_COMPONENT(ecs, Position);
    52 ECS_TAG(ecs, Tag); // Dummy tag to put entities in different tables
    53
    54 // Create a relationship to use for the group_by function. Tables will
    55 // be assigned the relationship target as group id
    56 ECS_TAG(ecs, Group);
    57
    58 // Targets for the relationship, which will be used as group ids.
    59 ECS_TAG(ecs, First);
    60 ECS_TAG(ecs, Second);
    61 ECS_TAG(ecs, Third);
    62
    63 // Grouped query
    64 ecs_query_t *q = ecs_query(ecs, {
    65 .terms = {
    66 { .id = ecs_id(Position) }
    67 },
    68 .group_by = Group,
    69 .on_group_create = on_group_create,
    70 .on_group_delete = on_group_delete
    71 });
    72
    73 // Create entities in 6 different tables with 3 group ids
    74 ecs_entity_t e1 = ecs_new_w_pair(ecs, Group, Third);
    75 ecs_set(ecs, e1, Position, {1, 1});
    76
    77 ecs_entity_t e2 = ecs_new_w_pair(ecs, Group, Second);
    78 ecs_set(ecs, e2, Position, {2, 2});
    79
    80 ecs_entity_t e3 = ecs_new_w_pair(ecs, Group, First);
    81 ecs_set(ecs, e3, Position, {3, 3});
    82
    83 ecs_entity_t e4 = ecs_new_w_pair(ecs, Group, Third);
    84 ecs_set(ecs, e4, Position, {4, 4});
    85 ecs_add(ecs, e4, Tag);
    86
    87 ecs_entity_t e5 = ecs_new_w_pair(ecs, Group, Second);
    88 ecs_set(ecs, e5, Position, {5, 5});
    89 ecs_add(ecs, e5, Tag);
    90
    91 ecs_entity_t e6 = ecs_new_w_pair(ecs, Group, First);
    92 ecs_set(ecs, e6, Position, {6, 6});
    93 ecs_add(ecs, e6, Tag);
    94
    95 // The query cache now looks like this:
    96 // - group First:
    97 // - table [Position, (Group, First)]
    98 // - table [Position, Tag, (Group, First)]
    99 //
    100 // - group Second:
    101 // - table [Position, (Group, Second)]
    102 // - table [Position, Tag, (Group, Second)]
    103 //
    104 // - group Third:
    105 // - table [Position, (Group, Third)]
    106 // - table [Position, Tag, (Group, Third)]
    107 //
    108
    109 printf("\n");
    110
    111 // Iterate query, print position & table components
    112 ecs_iter_t it = ecs_query_iter(ecs, q);
    113 while (ecs_query_next(&it)) {
    114 Position *p = ecs_field(&it, Position, 0);
    115 char *table_str = ecs_table_str(ecs, it.table);
    116
    117 uint64_t group_id = ecs_iter_get_group(&it);
    118 char *group_str = ecs_get_path(ecs, group_id);
    119 group_ctx *ctx = ecs_query_get_group_ctx(q, group_id);
    120
    121 printf(" - group %s: table [%s]\n", group_str, table_str);
    122 printf(" counter: %d\n", ctx->counter);
    123
    124 for (int i = 0; i < it.count; i ++) {
    125 printf(" {%f, %f}\n", p[i].x, p[i].y);
    126 }
    127
    128 ecs_os_free(group_str);
    129 ecs_os_free(table_str);
    130 printf("\n");
    131 }
    132
    133 // Deleting the query will call the on_group_deleted callback
    135
    136 // Output:
    137 // Group Third created
    138 // Group Second created
    139 // Group First created
    140 //
    141 // - group First: table [Position, (Group,First)]
    142 // counter: 3
    143 // {3.000000, 3.000000}
    144 //
    145 // - group First: table [Position, Tag, (Group,First)]
    146 // counter: 3
    147 // {6.000000, 6.000000}
    148 //
    149 // - group Second: table [Position, (Group,Second)]
    150 // counter: 2
    151 // {2.000000, 2.000000}
    152 //
    153 // - group Second: table [Position, Tag, (Group,Second)]
    154 // counter: 2
    155 // {5.000000, 5.000000}
    156 //
    157 // - group Third: table [Position, (Group,Third)]
    158 // counter: 1
    159 // {1.000000, 1.000000}
    160 //
    161 // - group Third: table [Position, Tag, (Group,Third)]
    162 // counter: 1
    163 // {4.000000, 4.000000}
    164 //
    165 // Group First deleted
    166 // Group Third deleted
    167 // Group Second deleted
    168
    169 return ecs_fini(ecs);
    170}
    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
    char * ecs_table_str(const ecs_world_t *world, const ecs_table_t *table)
    Convert a table to a string.
    #define ecs_add(world, entity, T)
    Add a component to an entity.
    Definition flecs_c.h:271
    #define ecs_new_w_pair(world, first, second)
    Create a new entity with a pair.
    Definition flecs_c.h:256
    #define ECS_COMPONENT(world, id)
    Declare and define a component.
    Definition flecs_c.h:98
    #define ECS_TAG(world, id)
    Declare and define a tag.
    Definition flecs_c.h:59
    #define ecs_query(world,...)
    Shorthand for creating a query with ecs_query_init().
    Definition flecs_c.h:215
    #define ecs_get_path(world, child)
    Get path from root.
    Definition flecs_c.h:594
    #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
    uint64_t ecs_iter_get_group(const ecs_iter_t *it)
    Return the group ID for the currently iterated result.
    const char * ecs_get_name(const ecs_world_t *world, ecs_entity_t entity)
    Get the name of an entity.
    bool ecs_query_next(ecs_iter_t *it)
    Progress a query iterator.
    void ecs_query_fini(ecs_query_t *query)
    Delete a query.
    ecs_iter_t ecs_query_iter(const ecs_world_t *world, const ecs_query_t *query)
    Create a query iterator.
    void * ecs_query_get_group_ctx(const ecs_query_t *query, uint64_t group_id)
    Get the context of a query group.
    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_table_t * table
    Current table.
    Definition flecs.h:1195
    int32_t count
    Number of entities to iterate.
    Definition flecs.h:1189
    Queries are lists of constraints (terms) that match entities.
    Definition flecs.h:858

  • C++

    View on GitHub

    1#include <group_by_callbacks.h>
    2#include <iostream>
    3
    4// This example shows how the on_group_create and on_group_delete callbacks can
    5// be used to get notified when a new group is registered for a query. These
    6// callbacks make it possible to associate and manage user data attached to
    7// groups.
    8
    9struct Position {
    10 double x, y;
    11};
    12
    13// Custom type to associate with group
    14struct group_ctx {
    15 int32_t counter;
    16};
    17
    18int group_counter = 0;
    19
    20// Dummy tag to put entities in different tables
    21struct Tag { };
    22
    23// Create a relationship to use for the group_by function. Tables will
    24// be assigned the relationship target as group id
    25struct Group { };
    26
    27// Targets for the relationship, which will be used as group ids.
    28struct First { };
    29struct Second { };
    30struct Third { };
    31
    32int main() {
    33 flecs::world ecs;
    34
    35 // Register components in order so that id for First is lower than Third
    36 ecs.component<First>();
    37 ecs.component<Second>();
    38 ecs.component<Third>();
    39
    40 // Grouped query
    41 flecs::query<Position> q = ecs.query_builder<Position>()
    42 .group_by<Group>()
    43
    44 // Callback invoked when a new group is created
    45 .on_group_create([](flecs::world_t *world,
    46 uint64_t id, // id of the group that was created
    47 void *group_by_arg) // group_by_ctx parameter in ecs_query_desc_t struct
    48 {
    49 (void)group_by_arg; // silence unused warning
    50 flecs::world w(world);
    51 std::cout << "Group " << w.entity(id).name() << " created\n";
    52
    53 // Return data that will be associated with the group
    54 group_ctx *ctx = new group_ctx;
    55 ctx->counter = ++ group_counter;
    56 return static_cast<void*>(ctx); // Cast to make sure function type matches
    57 })
    58
    59 // Callback invoked when a group is deleted
    60 .on_group_delete([](flecs::world_t *world,
    61 uint64_t id, // id of the group that was deleted
    62 void *ctx, // group context
    63 void *group_by_arg) // group_by_ctx parameter in ecs_query_desc_t struct
    64 {
    65 (void)group_by_arg; // silence unused warning
    66 flecs::world w(world);
    67 std::cout << "Group " << w.entity(id).name() << " deleted\n";
    68
    69 // Free data associated with group
    70 delete static_cast<group_ctx*>(ctx);
    71 })
    72 .build();
    73
    74 // Create entities in 6 different tables with 3 group ids
    75 ecs.entity().add<Group, Third>()
    76 .set<Position>({1, 1});
    77 ecs.entity().add<Group, Second>()
    78 .set<Position>({2, 2});
    79 ecs.entity().add<Group, First>()
    80 .set<Position>({3, 3});
    81
    82 ecs.entity().add<Group, Third>()
    83 .set<Position>({4, 4})
    84 .add<Tag>();
    85 ecs.entity().add<Group, Second>()
    86 .set<Position>({5, 5})
    87 .add<Tag>();
    88 ecs.entity().add<Group, First>()
    89 .set<Position>({6, 6})
    90 .add<Tag>();
    91
    92 // The query cache now looks like this:
    93 // - group First:
    94 // - table [Position, (Group, First)]
    95 // - table [Position, Tag, (Group, First)]
    96 //
    97 // - group Second:
    98 // - table [Position, (Group, Second)]
    99 // - table [Position, Tag, (Group, Second)]
    100 //
    101 // - group Third:
    102 // - table [Position, (Group, Third)]
    103 // - table [Position, Tag, (Group, Third)]
    104 //
    105
    106 std::cout << "\n";
    107
    108 q.run([&](flecs::iter& it) {
    109 while (it.next()) {
    110 auto p = it.field<Position>(0);
    111
    112 flecs::entity group = ecs.entity(it.group_id());
    113 group_ctx *ctx = static_cast<group_ctx*>(q.group_ctx(group));
    114
    115 std::cout << " - group " << group.path() << ": "
    116 << "table [" << it.table().str() << "]\n";
    117 std::cout << " counter: " << ctx->counter << "\n";
    118
    119 for (auto i : it) {
    120 std::cout << " {" << p[i].x << ", " << p[i].y << "}\n";
    121 }
    122
    123 std::cout << "\n";
    124 }
    125 });
    126
    127 // Deleting the query will call the on_group_deleted callback
    128 q.destruct();
    129
    130 // Output:
    131 // Group Third created
    132 // Group Second created
    133 // Group First created
    134 //
    135 // - group ::First: table [Position, (Group,First)]
    136 // counter: 3
    137 // {3, 3}
    138 //
    139 // - group ::First: table [Position, Tag, (Group,First)]
    140 // counter: 3
    141 // {6, 6}
    142 //
    143 // - group ::Second: table [Position, (Group,Second)]
    144 // counter: 2
    145 // {2, 2}
    146 //
    147 // - group ::Second: table [Position, Tag, (Group,Second)]
    148 // counter: 2
    149 // {5, 5}
    150 //
    151 // - group ::Third: table [Position, (Group,Third)]
    152 // counter: 1
    153 // {1, 1}
    154 //
    155 // - group ::Third: table [Position, Tag, (Group,Third)]
    156 // counter: 1
    157 // {4, 4}
    158 //
    159 // Group Third deleted
    160 // Group Second deleted
    161 // Group First deleted
    162}
    flecs::component< T > component(Args &&... args) const
    Find or register a component.
    Definition impl.hpp:11
    flecs::query_builder< Comps... > query_builder(Args &&... args) const
    Create a query builder.
    Definition impl.hpp:342
    flecs::entity entity(Args &&... args) const
    Create an entity.
    Definition impl.hpp:195
    ecs_world_t world_t
    World type.
    Definition c_types.hpp:18
    flecs::string path(const char *sep="::", const char *init_sep="::") const
    Return the entity path.
    Entity.
    Definition entity.hpp:30
    Class for iterating over query results.
    Definition iter.hpp:68
    flecs::field< A > field(int8_t index) const
    Get read-only access to field data.
    Definition iter.hpp:84
    flecs::table table() const
    Get the table for the current iterator result.
    Definition iter.hpp:67
    uint64_t group_id() const
    Return the group ID for the current table (grouped queries only).
    Definition iter.hpp:434
    bool next()
    Progress iterator.
    Definition iter.hpp:465
    Typed query.
    Definition impl.hpp:271
    flecs::string str() const
    Convert the table type to a string.
    Definition table.hpp:40
    The world.
    Definition world.hpp:129