Skip to content
Flecs v4.1
queries/transitive_queries

  • C

    View on GitHub

    1#include <transitive_queries.h>
    2#include <stdio.h>
    3
    4// Transitive relationships make it possible to tell the ECS that if an entity
    5// has a relationship (R, X) and X has relationship (R, Y), the entity should be
    6// treated as if it also has (R, Y). In practice this is useful for expressing
    7// things like:
    8//
    9// Bob lives in SanFrancisco
    10// San Francisco is located in the United States
    11// Therefore Bob also lives in the United States.
    12//
    13// An example of transitivity can be seen in the component_inheritance example.
    14// This example uses the builtin IsA relationship, which is transitive. This
    15// example shows how to achieve similar behavior with a user-defined relationship.
    16
    17int main(int argc, char *argv[]) {
    18 ecs_world_t *ecs = ecs_init_w_args(argc, argv);
    19
    20 // LocatedIn relationship
    21 ecs_entity_t LocatedIn = ecs_new(ecs);
    22 ecs_add_id(ecs, LocatedIn, EcsTransitive);
    23
    24 // Tags
    25 ECS_TAG(ecs, Planet);
    26 ECS_TAG(ecs, Continent);
    27 ECS_TAG(ecs, Country);
    28 ECS_TAG(ecs, State);
    29 ECS_TAG(ecs, City);
    30 ECS_TAG(ecs, Person);
    31
    32 // Populate the store with locations
    33 ecs_entity_t earth = ecs_entity(ecs, { .name = "Earth" });
    34 ecs_add(ecs, earth, Planet);
    35
    36 // Continents
    37 ecs_entity_t north_america = ecs_entity(ecs, { .name = "NorthAmerica" });
    38 ecs_add(ecs, north_america, Continent);
    39 ecs_add_pair(ecs, north_america, LocatedIn, earth);
    40
    41 ecs_entity_t europe = ecs_entity(ecs, { .name = "Europe" });
    42 ecs_add(ecs, europe, Continent);
    43 ecs_add_pair(ecs, europe, LocatedIn, earth);
    44
    45 // Countries
    46 ecs_entity_t united_states = ecs_entity(ecs, { .name = "UnitedStates" });
    47 ecs_add(ecs, united_states, Country);
    48 ecs_add_pair(ecs, united_states, LocatedIn, north_america);
    49
    50 ecs_entity_t netherlands = ecs_entity(ecs, { .name = "Netherlands" });
    51 ecs_add(ecs, netherlands, Country);
    52 ecs_add_pair(ecs, netherlands, LocatedIn, europe);
    53
    54 // States
    55 ecs_entity_t california = ecs_entity(ecs, { .name = "California" });
    56 ecs_add(ecs, california, State);
    57 ecs_add_pair(ecs, california, LocatedIn, united_states);
    58
    59 ecs_entity_t washington = ecs_entity(ecs, { .name = "Washington" });
    60 ecs_add(ecs, washington, State);
    61 ecs_add_pair(ecs, washington, LocatedIn, united_states);
    62
    63 ecs_entity_t noord_holland = ecs_entity(ecs, { .name = "NoordHolland" });
    64 ecs_add(ecs, noord_holland, State);
    65 ecs_add_pair(ecs, noord_holland, LocatedIn, netherlands);
    66
    67 // Cities
    68 ecs_entity_t san_francisco = ecs_entity(ecs, { .name = "SanFrancisco" });
    69 ecs_add(ecs, san_francisco, City);
    70 ecs_add_pair(ecs, san_francisco, LocatedIn, california);
    71
    72 ecs_entity_t seattle = ecs_entity(ecs, { .name = "Seattle" });
    73 ecs_add(ecs, seattle, City);
    74 ecs_add_pair(ecs, seattle, LocatedIn, washington);
    75
    76 ecs_entity_t amsterdam = ecs_entity(ecs, { .name = "Amsterdam" });
    77 ecs_add(ecs, amsterdam, City);
    78 ecs_add_pair(ecs, amsterdam, LocatedIn, noord_holland);
    79
    80 // Inhabitants
    81 ecs_entity_t bob = ecs_entity(ecs, { .name = "Bob" });
    82 ecs_add(ecs, bob, Person);
    83 ecs_add_pair(ecs, bob, LocatedIn, san_francisco);
    84
    85 ecs_entity_t alice = ecs_entity(ecs, { .name = "Alice" });
    86 ecs_add(ecs, alice, Person);
    87 ecs_add_pair(ecs, alice, LocatedIn, seattle);
    88
    89 ecs_entity_t job = ecs_entity(ecs, { .name = "Job" });
    90 ecs_add(ecs, job, Person);
    91 ecs_add_pair(ecs, job, LocatedIn, amsterdam);
    92
    93 // Create a query that finds the countries persons live in. Note that these
    94 // have not been explicitly added to the Person entities, but because the
    95 // LocatedIn is transitive, the query engine will traverse the relationship
    96 // until it found something that is a country.
    97 //
    98 // The equivalent of this query in the DSL is:
    99 // Person, (LocatedIn, $location), Country($location)
    100 ecs_query_t *q = ecs_query(ecs, {
    101 .terms = {
    102 { .id = Person },
    103 { .first.id = LocatedIn, .second.name = "$location" },
    104 { .first.id = Country, .src.name = "$location" }
    105 }
    106 });
    107
    108 // Lookup the index of the variable. This will let us quickly lookup its
    109 // value while we're iterating.
    110 int location_var = ecs_query_find_var(q, "location");
    111
    112 // Iterate the query
    113 ecs_iter_t it = ecs_query_iter(ecs, q);
    114 while (ecs_query_next(&it)) {
    115 ecs_entity_t location = ecs_iter_get_var(&it, location_var);
    116 for (int i = 0; i < it.count; i ++) {
    117 printf("%s lives in %s\n",
    118 ecs_get_name(ecs, it.entities[i]),
    119 ecs_get_name(ecs, location));
    120 }
    121 }
    122
    124
    125 // Output:
    126 // Bob lives in UnitedStates
    127 // Alice lives in UnitedStates
    128 // Job lives in Netherlands
    129
    130 return ecs_fini(ecs);
    131}
    void ecs_add_id(ecs_world_t *world, ecs_entity_t entity, ecs_id_t component)
    Add a (component) ID to an entity.
    const ecs_entity_t EcsTransitive
    Mark a relationship as transitive.
    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
    ecs_entity_t ecs_new(ecs_world_t *world)
    Create new entity ID.
    #define ecs_add_pair(world, subject, first, second)
    Add a pair to an entity.
    Definition flecs_c.h:275
    #define ecs_add(world, entity, T)
    Add a component to an entity.
    Definition flecs_c.h:271
    #define ecs_entity(world,...)
    Shorthand for creating an entity with ecs_entity_init().
    Definition flecs_c.h:188
    #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
    ecs_entity_t ecs_iter_get_var(ecs_iter_t *it, int32_t var_id)
    Get the value of an iterator variable as an entity.
    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.
    int32_t ecs_query_find_var(const ecs_query_t *query, const char *name)
    Find a variable index.
    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.
    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
    int32_t count
    Number of entities to iterate.
    Definition flecs.h:1189
    const ecs_entity_t * entities
    Entity identifiers.
    Definition flecs.h:1190
    Queries are lists of constraints (terms) that match entities.
    Definition flecs.h:858

  • C++

    View on GitHub

    1#include <transitive_queries.h>
    2#include <iostream>
    3
    4// Transitive relationships make it possible to tell the ECS that if an entity
    5// has a relationship (R, X) and X has relationship (R, Y), the entity should be
    6// treated as if it also has (R, Y). In practice this is useful for expressing
    7// things like:
    8//
    9// Bob lives in SanFrancisco
    10// San Francisco is located in the United States
    11// Therefore Bob also lives in the United States.
    12//
    13// An example of transitivity can be seen in the component_inheritance example.
    14// This example uses the builtin IsA relationship, which is transitive. This
    15// example shows how to achieve similar behavior with a user-defined relationship.
    16
    17struct LocatedIn { };
    18struct Planet { };
    19struct Continent { };
    20struct Country { };
    21struct State { };
    22struct City { };
    23struct Person { };
    24
    25int main(int, char *[]) {
    26 flecs::world ecs;
    27
    28 // Register the LocatedIn relationship as transitive
    29 ecs.component<LocatedIn>().add(flecs::Transitive);
    30
    31 // Populate the store with locations
    32 flecs::entity earth = ecs.entity("Earth")
    33 .add<Planet>();
    34
    35 // Continents
    36 flecs::entity north_america = ecs.entity("NorthAmerica")
    37 .add<Continent>()
    38 .add<LocatedIn>(earth);
    39
    40 flecs::entity europe = ecs.entity("Europe")
    41 .add<Continent>()
    42 .add<LocatedIn>(earth);
    43
    44 // Countries
    45 flecs::entity united_states = ecs.entity("UnitedStates")
    46 .add<Country>()
    47 .add<LocatedIn>(north_america);
    48
    49 flecs::entity netherlands = ecs.entity("Netherlands")
    50 .add<Country>()
    51 .add<LocatedIn>(europe);
    52
    53 // States
    54 flecs::entity california = ecs.entity("California")
    55 .add<State>()
    56 .add<LocatedIn>(united_states);
    57
    58 flecs::entity washington = ecs.entity("Washington")
    59 .add<State>()
    60 .add<LocatedIn>(united_states);
    61
    62 flecs::entity noord_holland = ecs.entity("NoordHolland")
    63 .add<State>()
    64 .add<LocatedIn>(netherlands);
    65
    66 // Cities
    67 flecs::entity san_francisco = ecs.entity("SanFrancisco")
    68 .add<City>()
    69 .add<LocatedIn>(california);
    70
    71 flecs::entity seattle = ecs.entity("Seattle")
    72 .add<City>()
    73 .add<LocatedIn>(washington);
    74
    75 flecs::entity amsterdam = ecs.entity("Amsterdam")
    76 .add<City>()
    77 .add<LocatedIn>(noord_holland);
    78
    79 // Inhabitants
    80 ecs.entity("Bob")
    81 .add<Person>()
    82 .add<LocatedIn>(san_francisco);
    83
    84 ecs.entity("Alice")
    85 .add<Person>()
    86 .add<LocatedIn>(seattle);
    87
    88 ecs.entity("Job")
    89 .add<Person>()
    90 .add<LocatedIn>(amsterdam);
    91
    92 // Create a query that finds the countries persons live in. Note that these
    93 // have not been explicitly added to the Person entities, but because the
    94 // LocatedIn is transitive, the query engine will traverse the relationship
    95 // until it found something that is a country.
    96 //
    97 // The equivalent of this query in the DSL is:
    98 // Person, (LocatedIn, $location), Country($location)
    100 .with<Person>()
    101 .with<LocatedIn>("$location")
    102 .with<Country>().src("$location")
    103 .build();
    104
    105 // Lookup the index of the variable. This will let us quickly lookup its
    106 // value while we're iterating.
    107 int location_var = q.find_var("location");
    108
    109 // Iterate the query
    110 q.each([&](flecs::iter& it, size_t index) {
    111 std::cout
    112 << it.entity(index).name()
    113 << " lives in " << it.get_var(location_var).name()
    114 << "\n";
    115 });
    116
    117 // Output:
    118 // Bob lives in UnitedStates
    119 // Alice lives in UnitedStates
    120 // Job lives in Netherlands
    121}
    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
    flecs::string_view name() const
    Return the entity name.
    Entity.
    Definition entity.hpp:30
    Class for iterating over query results.
    Definition iter.hpp:68
    flecs::entity entity(size_t row) const
    Obtain a mutable handle to the entity being iterated over.
    Definition iter.hpp:36
    flecs::entity get_var(int var_id) const
    Get value of variable by ID.
    Definition iter.hpp:128
    void each(Func &&func) const
    Each iterator.
    Definition iterable.hpp:37
    int32_t find_var(const char *name) const
    Find a variable by name.
    Definition impl.hpp:203
    Typed query.
    Definition impl.hpp:271
    The world.
    Definition world.hpp:129