Skip to content
Flecs v4.1
systems/sync_point

  • C

    View on GitHub

    1#include <sync_point.h>
    2#include <stdio.h>
    3
    4typedef struct {
    5 double x, y;
    6} Position, Velocity;
    7
    8// Forward declare components so they can be accessed from systems
    10ECS_COMPONENT_DECLARE(Velocity);
    11
    12void SetVelocity(ecs_iter_t *it) {
    13 for (int i = 0; i < it->count; i ++) {
    14 ecs_set(it->stage, it->entities[i], Velocity, {1, 2});
    15 }
    16}
    17
    18void Move(ecs_iter_t *it) {
    19 Position *p = ecs_field(it, Position, 0);
    20 const Velocity *v = ecs_field(it, const Velocity, 1);
    21
    22 for (int i = 0; i < it->count; i ++) {
    23 p[i].x += v[i].x;
    24 p[i].y += v[i].y;
    25 }
    26}
    27
    28void PrintPosition(ecs_iter_t *it) {
    29 const Position *p = ecs_field(it, const Position, 0);
    30
    31 for (int i = 0; i < it->count; i ++) {
    32 printf("%s: {%f, %f}\n", ecs_get_name(it->stage, it->entities[i]),
    33 p[i].x, p[i].y);
    34 }
    35}
    36
    37int main(int argc, char *argv[]) {
    38 ecs_world_t *ecs = ecs_init_w_args(argc, argv);
    39
    40 ECS_COMPONENT_DEFINE(ecs, Position);
    41 ECS_COMPONENT_DEFINE(ecs, Velocity);
    42
    43 // System that sets velocity using set<T> for entities with Position.
    44 // While systems are progressing, operations like set<T> are deferred until
    45 // it is safe to merge. By default this merge happens at the end of the
    46 // frame, but we can annotate systems to give the scheduler more information
    47 // about what it's doing, which allows it to insert sync points earlier.
    48 //
    49 // The parentheses after Velocity indicate that the component is not used
    50 // to match entities, while [out] indicates that it is written. A subsequent
    51 // system that accesses the component will cause the scheduler to insert a
    52 // sync point.
    53 //
    54 // Note that sync points are never necessary/inserted for systems that write
    55 // components provided by their signature, as these writes directly happen
    56 // in the ECS storage and are never deferred.
    57 //
    58 // The [none] annotation for Position tells the scheduler that while we
    59 // want to match entities with Position, we're not interested in reading or
    60 // writing the component value.
    61 ECS_SYSTEM(ecs, SetVelocity, EcsOnUpdate, [none] Position, [out] Velocity());
    62
    63 // This system reads Velocity, which causes the insertion of a sync point.
    64 ECS_SYSTEM(ecs, Move, EcsOnUpdate, Position, [in] Velocity);
    65
    66 // Print resulting Position
    67 ECS_SYSTEM(ecs, PrintPosition, EcsPostUpdate, [in] Position);
    68
    69 // Create a few test entities for a Position, Velocity query
    70 ecs_entity_t e1 = ecs_entity(ecs, { .name = "e1" });
    71 ecs_set(ecs, e1, Position, {10, 20});
    72 ecs_set(ecs, e1, Velocity, {1, 2});
    73
    74 ecs_entity_t e2 = ecs_entity(ecs, { .name = "e2" });
    75 ecs_set(ecs, e2, Position, {10, 20});
    76 ecs_set(ecs, e2, Velocity, {3, 4});
    77
    78 // Run systems. Debug logging enables us to see the generated schedule
    80 ecs_progress(ecs, 0.0f);
    81 ecs_log_set_level(-1); // Restore so we don't get world cleanup logs
    82
    83 // Output:
    84 // info: pipeline rebuild:
    85 // info: | schedule: threading: 0, staging: 1:
    86 // info: | | system SetVelocity
    87 // info: | | merge
    88 // info: | schedule: threading: 0, staging: 1:
    89 // info: | | system Move
    90 // info: | | system PrintPosition
    91 // info: | | merge
    92 // e1: {11.000000, 22.000000}
    93 // e2: {11.000000, 22.000000}
    94 //
    95 // The "merge" lines indicate sync points.
    96 //
    97 // Removing the '[out] Velocity()' annotation from the system will remove
    98 // the first sync point from the schedule.
    99 //
    100 // To create the same system with ecs_system_init, do:
    101 // ecs_system_init(ecs, &(ecs_system_desc_t){
    102 // .query.terms = {
    103 // {
    104 // .id = ecs_id(Position),
    105 // .inout = EcsInOutNone
    106 // },
    107 // {
    108 // .id = ecs_id(Velocity),
    109 // .inout = EcsOut,
    110 // .src.id = EcsIsEntity
    111 // }
    112 // },
    113 // .entity = {
    114 // .name = "SetVelocity"
    115 // },
    116 // .phase = EcsOnUpdate,
    117 // .callback = SetVelocity
    118 // });
    119
    120 return ecs_fini(ecs);
    121}
    const ecs_entity_t EcsPostUpdate
    PostUpdate pipeline phase.
    const ecs_entity_t EcsOnUpdate
    OnUpdate pipeline phase.
    FLECS_API int ecs_log_set_level(int level)
    Enable or disable log.
    FLECS_API bool ecs_progress(ecs_world_t *world, ecs_ftime_t delta_time)
    Progress a world.
    #define ECS_SYSTEM(world, id, phase,...)
    Declare and define a system.
    Definition system.h:263
    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_entity(world,...)
    Shorthand for creating an entity with ecs_entity_init().
    Definition flecs_c.h:188
    #define ECS_COMPONENT_DEFINE(world, id_)
    Define a forward-declared component.
    Definition flecs_c.h:75
    #define ECS_COMPONENT_DECLARE(id)
    Forward declare a component.
    Definition flecs_c.h:65
    #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
    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 <sync_point.h>
    2#include <iostream>
    3
    4struct Position {
    5 double x, y;
    6};
    7
    8struct Velocity {
    9 double x, y;
    10};
    11
    12int main(int, char *[]) {
    13 flecs::world ecs;
    14
    15 // System that sets velocity using ecs_set for entities with Position.
    16 // While systems are progressing, operations like ecs_set are deferred until
    17 // it is safe to merge. By default this merge happens at the end of the
    18 // frame, but we can annotate systems to give the scheduler more information
    19 // about what it's doing, which allows it to insert sync points earlier.
    20 //
    21 // Note that sync points are never necessary/inserted for systems that write
    22 // components provided by their signature, as these writes directly happen
    23 // in the ECS storage and are never deferred.
    24 //
    25 // .inout_none() for Position tells the scheduler that while we
    26 // want to match entities with Position, we're not interested in reading or
    27 // writing the component value.
    28 ecs.system("SetVelocity")
    29 .with<Position>().inout_none()
    30 .write<Velocity>() // Velocity is written, but shouldn't be matched
    31 .each([](flecs::entity e) {
    32 e.set<Velocity>({1, 2});
    33 });
    34
    35 // This system reads Velocity, which causes the insertion of a sync point.
    36 ecs.system<Position, const Velocity>("Move")
    37 .each([](Position& p, const Velocity& v) {
    38 p.x += v.x;
    39 p.y += v.y;
    40 });
    41
    42 // Print resulting Position
    43 ecs.system<const Position>("PrintPosition")
    44 .each([](flecs::entity e, const Position& p) {
    45 std::cout << e.name() << ": {" << p.x << ", " << p.y << "}\n";
    46 });
    47
    48 // Create a few test entities for a Position, Velocity query
    49 ecs.entity("e1")
    50 .set<Position>({10, 20})
    51 .set<Velocity>({1, 2});
    52
    53 ecs.entity("e2")
    54 .set<Position>({10, 20})
    55 .set<Velocity>({3, 4});
    56
    57 // Run systems. Debug logging enables us to see the generated schedule
    59 ecs.progress();
    60 flecs::log::set_level(-1); // Restore so we don't get world cleanup logs
    61
    62 // Output:
    63 // info: pipeline rebuild:
    64 // info: | schedule: threading: 0, staging: 1:
    65 // info: | | system SetVelocity
    66 // info: | | merge
    67 // info: | schedule: threading: 0, staging: 1:
    68 // info: | | system Move
    69 // info: | | system PrintPosition
    70 // info: | | merge
    71 // e1: {11.000000, 22.000000}
    72 // e2: {11.000000, 22.000000}
    73 //
    74 // The "merge" lines indicate sync points.
    75 //
    76 // Removing '.write<Velocity>()' from the system will remove the first
    77 // sync point from the schedule.
    78}
    flecs::system system(flecs::entity e) const
    Upcast an entity to a system.
    Definition impl.hpp:181
    flecs::entity entity(Args &&... args) const
    Create an entity.
    Definition impl.hpp:195
    void set_level(int level)
    Set the log level.
    Definition log.hpp:57
    bool progress(ecs_ftime_t delta_time=0.0) const
    Progress the world one tick.
    Definition impl.hpp:47
    flecs::string_view name() const
    Return the entity name.
    Entity.
    Definition entity.hpp:30
    The world.
    Definition world.hpp:129
    void each(Func &&func) const
    Iterate over all entities with components in the argument list of the function.