flecs

CI build codecov Discord Chat Try online Documentation

Flecs is a fast and lightweight Entity Component System with a focus on high performance game development (join the Discord!). Highlights of the framework are:

  • Fast to compile & integrate in any project with zero-dependency core that is written entirely in C99
  • Highly portable with C++11 API that does not depend on any STL types
  • Provides (SoA) access to raw component arrays for optimal cache efficiency and vectorization
  • Archetype-storage with unique graph-based design enables high performance entity mutations
  • Flexible API primitives allow for efficient implementation of prefabs, runtime tags and entity graphs
  • Supports advanced queries that are entirely evaluated offline to eliminate searching from the main loop
  • Lockless threading design allows for efficient execution of systems on multiple threads
  • A dashboard module for tracking application metrics (see below for repository link):
Screen Shot 2020-12-02 at 1 28 04 AM

What is an Entity Component System?

ECS (Entity Component System) is a design pattern used in games and simulations that produces fast and reusable code. Dynamic composition is a first-class citizen in ECS, and there is a strict separation between data and behavior. A framework is an Entity Component System if it:

  • Has entities that are unique identifiers
  • Has components that are plain data types
  • Has systems which are behavior matched with entities based on their components

Documentation

If you are still learning Flecs, these resources are a good start:

The FAQ is where some of the most asked questions are listed:

The manual and examples come in handy if you're looking for information on specific features:

If you are migrating from Flecs v1 to v2, check the migration guide:

Here is some awesome content provided by the community (thanks everyone! :heart:):

Examples

This is a simple flecs example in the C99 API:

typedef struct {
  float x;
  float y;
} Position, Velocity;

void Move(ecs_iter_t *it) {
  Position *p = ecs_term(it, Position, 1);
  Velocity *v = ecs_term(it, Velocity, 2);
  
  for (int i = 0; i < it->count; i ++) {
    p[i].x += v[i].x * it->delta_time;
    p[i].y += v[i].y * it->delta_time;
    printf("Entity %s moved!\n", ecs_get_name(it->world, it->entities[i]));
  }
}

int main(int argc, char *argv[]) {
  ecs_world_t *ecs = ecs_init();

  // Register the Position component
  ecs_entity_t pos = ecs_component_init(ecs, &(ecs_component_desc_t){
    .entity.name = "Position",
    .size = sizeof(Position), .alignment = ECS_ALIGNOF(Position)
  });

  // Register the Velocity component
  ecs_entity_t vel = ecs_component_init(ecs, &(ecs_component_desc_t){
    .entity.name = "Velocity",
    .size = sizeof(Velocity), .alignment = ECS_ALIGNOF(Velocity)
  });

  // Create the Move system
  ecs_system_init(ecs, &(ecs_system_desc_t){
    .entity = { .name = "Move", .add = {EcsOnUpdate} },
    .query.filter.terms = {{pos}, {vel, .inout = EcsIn}},
    .callback = Move,
  });

  // Create a named entity
  ecs_entity_t e = ecs_entity_init(ecs, &(ecs_entity_desc_t){
    .name = "MyEntity"
  });

  // Set components
  ecs_set_id(ecs, e, pos, sizeof(Position), &(Position){0, 0});
  ecs_set_id(ecs, e, vel, sizeof(Velocity), &(Velocity){1, 1});

  // Run the main loop
  while (ecs_progress(ecs, 0)) { }
}

Because C99 lacks generics, the API provides a number of convenience macro's that reduce boilerplate & improve type safety. This is the same example with macro's (system implementation ommitted since it doesn't change):

int main(int argc, char *argv[]) {
  ecs_world_t *ecs = ecs_init();

  ECS_COMPONENT(ecs, Position);
  ECS_COMPONENT(ecs, Velocity);

  ECS_SYSTEM(ecs, Move, EcsOnUpdate, Position, [in] Velocity);

  ecs_entity_t e = ecs_entity_init(ecs, &(ecs_entity_desc_t){
    .name = "MyEntity"
  });

  ecs_set(ecs, e, Position, {0, 0});
  ecs_set(ecs, e, Velocity, {1, 1});

  while (ecs_progress(ecs, 0)) { }
}

This is the same example in the C++11 API:

struct Position {
  float x;
  float y;
};

struct Velocity {
  float x;
  float y;
};

int main(int argc, char *argv[]) {
  flecs::world ecs;

  ecs.system<Position, const Velocity>()
    .each([](flecs::entity e, Position& p, const Velocity& v) {
      p.x += v.x * e.delta_time();
      p.y += v.y * e.delta_time();
      std::cout << "Entity " << e.name() << " moved!" << std::endl;
    });

  ecs.entity("MyEntity")
    .set<Position>({0, 0})
    .set<Velocity>({1, 1});

  while (ecs.progress()) { }
}

Building

The easiest way to add Flecs to a project is to add flecs.c and flecs.h to your source code. These files can be added to both C and C++ projects (the C++ API is embedded in flecs.h). Alternatively you can also build Flecs as a library by using the cmake, meson, bazel or bake buildfiles.

Custom builds

The Flecs source has a modular design which makes it easy to strip out code you don't need. At its core, Flecs is a minimalistic ECS library with a lot of optional features that you can choose to include or not. This section of the manual describes how to customize which features to include.

Software Quality

To ensure stability of Flecs, the code is thoroughly tested on every commit:

  • 40.000 lines of test code, for 18.000 lines of framework code
  • More than 1600 testcases
  • Over 90% code coverage

The code is validated on the following platforms/compilers:

  • Windows
    • msvc
  • Ubuntu
    • gcc 7, 8, 9, 10
    • clang 8, 9
  • MacOS
    • gcc 10
    • clang 9

The framework code and example code is compiled warning free on all platforms with the strictest warning settings. A sanitized build is ran on each commit to test for memory corruption and undefined behavior.

Performance is tracked on a per-release basis, with the results for the latest release published here: https://github.com/SanderMertens/ecs_benchmark

API stability

API (programming interface) stability is guaranteed between minor releases, except in the rare case when an API is found to be an obvious source of confusion or bugs. When breaking changes do happen, the release notes will mention it with potential workarounds.

ABI (binary interface) stability is not guaranteed inbetween versions, as non-opaque types and signatures may change at any point in time, as long as they don't break compilation of code that uses the public API. Headers under include/private are not part of the public API, and may introduce breaking changes at any point.

It is generally safe to use the master branch, which contains the latest version of the code. New features that are on master but are not yet part of a release may still see changes in their API. Once a feature is part of a release, its API will not change until at least the next major release.

Modules

The following modules are available in flecs-hub. Note that modules are mostly intended as example code, and their APIs may change at any point in time.

Module Description
flecs.meta Reflection for Flecs components
flecs.json JSON serializer for Flecs components
flecs.rest A REST interface for introspecting & editing entities
flecs.player Play, stop and pause simulations
flecs.monitor Web-based monitoring of statistics
flecs.dash Web-based dashboard for remote monitoring and debugging of Flecs apps
flecs.components.input Components that describe keyboard and mouse input
flecs.components.transform Components that describe position, rotation and scale
flecs.components.physics Components that describe physics and movement
flecs.components.geometry Components that describe geometry
flecs.components.graphics Components used for computer graphics
flecs.components.gui Components used to describe GUI components
flecs.components.http Components describing an HTTP server
flecs.systems.transform Hierarchical transforms for scene graphs
flecs.systems.sdl2 SDL window creation & input management
flecs.systems.sokol Sokol-based renderer
flecs.systems.civetweb A civetweb-based implementation of flecs.components.http

Language bindings

Supporting Flecs

Supporting Flecs goes a long way towards keeping the project going and the community alive! If you like the project, consider:

Thanks in advance!