Skip to content
Flecs v4.1
queries/group_iter

  • C

    View on GitHub

    1#include <group_iter.h>
    2#include <stdio.h>
    3
    4// A group iterator iterates over a single group of a grouped query (see the
    5// group_by example for more details). This can be useful when an application
    6// may need to match different entities based on the context of the game, such
    7// as editor mode, day/night, inside/outside or location in the world.
    8//
    9// One example is that of an open game which is divided up into world
    10// cells. Even though a world may contain many entities, only the entities in
    11// cells close to the player need to be processed.
    12//
    13// Instead of creating a cached query per world cell, which could be expensive
    14// as there are more caches to keep in sync, applications can create a single
    15// query grouped by world cell, and use group iterators to only iterate the
    16// necessary cells.
    17
    18uint64_t group_by_relation(ecs_world_t *ecs, ecs_table_t *table,
    19 ecs_entity_t id, void *ctx)
    20{
    21 (void)ctx; // marks ctx as unused, avoids compiler warnings
    22
    23 // Use ecs_search to find the target for the relationship in the table
    24 ecs_id_t match;
    25 if (ecs_search(ecs, table, ecs_pair(id, EcsWildcard), &match) != -1) {
    26 return ecs_pair_second(ecs, match); // World cell is 2nd element of pair
    27 }
    28
    29 return 0;
    30}
    31
    32int main(int argc, char *argv[]) {
    33 ecs_world_t *ecs = ecs_init_w_args(argc, argv);
    34
    35 // A world cell relationship with four cells
    36 ECS_TAG(ecs, WorldCell);
    37 ECS_TAG(ecs, Cell_0_0);
    38 ECS_TAG(ecs, Cell_0_1);
    39 ECS_TAG(ecs, Cell_1_0);
    40 ECS_TAG(ecs, Cell_1_1);
    41
    42 // Npc tags
    43 ECS_TAG(ecs, Npc);
    44 ECS_TAG(ecs, Merchant);
    45 ECS_TAG(ecs, Soldier);
    46 ECS_TAG(ecs, Beggar);
    47 ECS_TAG(ecs, Mage);
    48
    49 // Create Npcs in world cell 0_0
    50 ecs_entity_t npc_01 = ecs_new_w_pair(ecs, WorldCell, Cell_0_0);
    51 ecs_add(ecs, npc_01, Merchant);
    52 ecs_add(ecs, npc_01, Npc);
    53 ecs_entity_t npc_02 = ecs_new_w_pair(ecs, WorldCell, Cell_0_0);
    54 ecs_add(ecs, npc_02, Merchant);
    55 ecs_add(ecs, npc_02, Npc);
    56
    57 // Create Npcs in world cell 0_1
    58 ecs_entity_t npc_03 = ecs_new_w_pair(ecs, WorldCell, Cell_0_1);
    59 ecs_add(ecs, npc_03, Beggar);
    60 ecs_add(ecs, npc_03, Npc);
    61 ecs_entity_t npc_04 = ecs_new_w_pair(ecs, WorldCell, Cell_0_1);
    62 ecs_add(ecs, npc_04, Soldier);
    63 ecs_add(ecs, npc_04, Npc);
    64
    65 // Create Npcs in world cell 1_0
    66 ecs_entity_t npc_05 = ecs_new_w_pair(ecs, WorldCell, Cell_1_0);
    67 ecs_add(ecs, npc_05, Mage);
    68 ecs_add(ecs, npc_05, Npc);
    69 ecs_entity_t npc_06 = ecs_new_w_pair(ecs, WorldCell, Cell_1_0);
    70 ecs_add(ecs, npc_06, Beggar);
    71 ecs_add(ecs, npc_06, Npc);
    72
    73 // Create Npcs in world cell 1_1
    74 ecs_entity_t npc_07 = ecs_new_w_pair(ecs, WorldCell, Cell_1_1);
    75 ecs_add(ecs, npc_07, Soldier);
    76 ecs_add(ecs, npc_07, Npc);
    77
    78 // Create a query that matches all Npc's, grouped by WorldCell
    79 ecs_query_t *q = ecs_query(ecs, {
    80 .terms = {
    81 { .id = Npc }
    82 },
    83 .group_by_callback = group_by_relation,
    84 .group_by = WorldCell
    85 });
    86
    87 // Iterate all tables
    88 printf("All tables:\n");
    89 ecs_iter_t it = ecs_query_iter(ecs, q);
    90 while (ecs_query_next(&it)) {
    91 char *table_str = ecs_table_str(ecs, it.table);
    92 char *group_str = ecs_get_path(ecs, ecs_iter_get_group(&it));
    93
    94 printf(" - group %s: table [%s]\n", group_str, table_str);
    95
    96 // Uncomment to iterate entities in table
    97 // for (int i = 0; i < it.count; i ++) { }
    98
    99 ecs_os_free(group_str);
    100 ecs_os_free(table_str);
    101 }
    102 printf("\n");
    103
    104 // Only iterate entities in cell 1_0
    105 printf("Tables for cell 1_0:\n");
    106 it = ecs_query_iter(ecs, q);
    107 ecs_iter_set_group(&it, Cell_1_0);
    108 while (ecs_query_next(&it)) {
    109 char *table_str = ecs_table_str(ecs, it.table);
    110 char *group_str = ecs_get_path(ecs, ecs_iter_get_group(&it));
    111
    112 printf(" - group %s: table [%s]\n", group_str, table_str);
    113
    114 ecs_os_free(group_str);
    115 ecs_os_free(table_str);
    116 }
    117
    118 // Output:
    119 // All tables:
    120 // - group Cell_0_0: table [Npc, Merchant, (WorldCell,Cell_0_0)]
    121 // - group Cell_0_1: table [Npc, Beggar, (WorldCell,Cell_0_1)]
    122 // - group Cell_0_1: table [Npc, Soldier, (WorldCell,Cell_0_1)]
    123 // - group Cell_1_0: table [Npc, Mage, (WorldCell,Cell_1_0)]
    124 // - group Cell_1_0: table [Npc, Beggar, (WorldCell,Cell_1_0)]
    125 // - group Cell_1_1: table [Npc, Soldier, (WorldCell,Cell_1_1)]
    126 //
    127 // Tables for cell 1_0:
    128 // - group Cell_1_0: table [Npc, Mage, (WorldCell,Cell_1_0)]
    129 // - group Cell_1_0: table [Npc, Beggar, (WorldCell,Cell_1_0)]
    130
    131 return ecs_fini(ecs);
    132}
    const ecs_entity_t EcsWildcard
    Wildcard entity ("*").
    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
    uint64_t ecs_id_t
    IDs are the things that can be added to an entity.
    Definition flecs.h:388
    struct ecs_table_t ecs_table_t
    A table stores entities and components for a specific type.
    Definition flecs.h:445
    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_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
    uint64_t ecs_iter_get_group(const ecs_iter_t *it)
    Return the group ID for the currently iterated result.
    void ecs_iter_set_group(ecs_iter_t *it, uint64_t group_id)
    Set the group to iterate for a query iterator.
    bool ecs_query_next(ecs_iter_t *it)
    Progress a query iterator.
    ecs_iter_t ecs_query_iter(const ecs_world_t *world, const ecs_query_t *query)
    Create a query iterator.
    int32_t ecs_search(const ecs_world_t *world, const ecs_table_t *table, ecs_id_t component, ecs_id_t *component_out)
    Search for a component in a table type.
    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
    Queries are lists of constraints (terms) that match entities.
    Definition flecs.h:858

  • C++

    View on GitHub

    1#include <group_iter.h>
    2#include <iostream>
    3
    4// A group iterator iterates over a single group of a grouped query (see the
    5// group_by example for more details). This can be useful when an application
    6// may need to match different entities based on the context of the game, such
    7// as editor mode, day/night, inside/outside or location in the world.
    8//
    9// One example is that of an open game which is divided up into world
    10// cells. Even though a world may contain many entities, only the entities in
    11// cells close to the player need to be processed.
    12//
    13// Instead of creating a cached query per world cell, which could be expensive
    14// as there are more caches to keep in sync, applications can create a single
    15// query grouped by world cell, and use group iterators to only iterate the
    16// necessary cells.
    17
    18// A world cell relationship with four cells
    19struct WorldCell {};
    20struct Cell_0_0 {};
    21struct Cell_0_1 {};
    22struct Cell_1_0 {};
    23struct Cell_1_1 {};
    24
    25// Npc tags
    26struct Npc {};
    27struct Merchant {};
    28struct Soldier {};
    29struct Beggar {};
    30struct Mage {};
    31
    32int main() {
    33 flecs::world ecs;
    34
    35 // Create npc's in world cell 0_0
    36 ecs.entity().add<WorldCell, Cell_0_0>()
    37 .add<Merchant>()
    38 .add<Npc>();
    39 ecs.entity().add<WorldCell, Cell_0_0>()
    40 .add<Merchant>()
    41 .add<Npc>();
    42
    43 // Create npc's in world cell 0_1
    44 ecs.entity().add<WorldCell, Cell_0_1>()
    45 .add<Beggar>()
    46 .add<Npc>();
    47 ecs.entity().add<WorldCell, Cell_0_1>()
    48 .add<Soldier>()
    49 .add<Npc>();
    50
    51 // Create npc's in world cell 1_0
    52 ecs.entity().add<WorldCell, Cell_1_0>()
    53 .add<Mage>()
    54 .add<Npc>();
    55 ecs.entity().add<WorldCell, Cell_1_0>()
    56 .add<Beggar>()
    57 .add<Npc>();
    58
    59 // Create npc's in world cell 1_1
    60 ecs.entity().add<WorldCell, Cell_1_1>()
    61 .add<Soldier>()
    62 .add<Npc>();
    63
    64 flecs::query<Npc> q = ecs.query_builder<Npc>()
    65 .group_by<WorldCell>()
    66 .build();
    67
    68 // Iterate all tables
    69 std::cout << "All tables:\n";
    70 q.run([&](flecs::iter& it) {
    71 while (it.next()) {
    72 flecs::entity group = ecs.entity(it.group_id());
    73 std::cout << " - group " << group.path() << ": table ["
    74 << it.table().str() << "]\n";
    75 }
    76 });
    77
    78 std::cout << "\n";
    79
    80 // Only iterate entities in cell 1_0
    81 std::cout << "Tables for cell 1_0:\n";
    82 q.set_group<Cell_1_0>().run([&](flecs::iter& it) {
    83 while (it.next()) {
    84 flecs::entity group = ecs.entity(it.group_id());
    85 std::cout << " - group " << group.path() << ": table ["
    86 << it.table().str() << "]\n";
    87 }
    88 });
    89
    90 // Output:
    91 // All tables:
    92 // - group ::Cell_0_0: table [Merchant, Npc, (WorldCell,Cell_0_0)]
    93 // - group ::Cell_0_1: table [Npc, Beggar, (WorldCell,Cell_0_1)]
    94 // - group ::Cell_0_1: table [Npc, Soldier, (WorldCell,Cell_0_1)]
    95 // - group ::Cell_1_0: table [Npc, Mage, (WorldCell,Cell_1_0)]
    96 // - group ::Cell_1_0: table [Npc, Beggar, (WorldCell,Cell_1_0)]
    97 // - group ::Cell_1_1: table [Npc, Soldier, (WorldCell,Cell_1_1)]
    98 //
    99 // Tables for cell 1_0:
    100 // - group ::Cell_1_0: table [Npc, Mage, (WorldCell,Cell_1_0)]
    101 // - group ::Cell_1_0: table [Npc, Beggar, (WorldCell,Cell_1_0)]
    102}
    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
    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::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