Flecs is a high-performance Entity Component System (ECS) designed specifically for game development and real-time simulation systems. It is written in C99 and provides a C++11 wrapper, emphasizing performance, low overhead, and a modular architecture.
📦 Core Features Overview
The table below summarizes the main features of Flecs:
| Feature Category | Details |
|---|---|
| Architecture Pattern | Entity Component System (ECS), Data-Oriented Design |
| Performance Characteristics | High performance, cache-friendly, low memory overhead |
| Language Support | Native C99, with bindings for C++11, Lua, Python, etc. |
| Modularity | Modular system with pluggable features |
| Tool Ecosystem | Flecs Hub provides ready-to-use modules (e.g., 2D/3D transformations, serialization, etc.) |
🛠️ Installation and Project Configuration
Installation Methods
Flecs can be installed in several ways:
- Package Manager Installation:
# Vcpkg vcpkg install flecs
Conan
conan install flecs/3.1.0
2. **Source Integration**:
```bash
git clone https://github.com/SanderMertens/flecs.git
cd flecs
mkdir build && cd build
cmake ..
make
Using in Code
// C++ version
#include <flecs.h>
// C version
#include <flecs.h>
Using CMake Integration
cmake_minimum_required(VERSION 3.10)
project(MyGame)
find_package(flecs REQUIRED)
add_executable(my_game main.cpp)
target_link_libraries(my_game flecs::flecs)
🚀 Basic Usage and Core Concepts
1. Basic ECS Concepts
#include <flecs.h>
#include <iostream>
// Define components
struct Position {
float x, y;
};
struct Velocity {
float x, y;
};
struct Health {
int current;
int max;
};
int main() {
// Create world
flecs::world world;
// Register components
world.component<Position>();
world.component<Velocity>();
world.component<Health>();
// Create entity and add components
auto player = world.entity("Player")
.set<Position>({10.0f, 20.0f})
.set<Velocity>({1.0f, 0.0f})
.set<Health>({100, 100});
// Create more entities
for (int i = 0; i < 5; ++i) {
world.entity()
.set<Position>({static_cast<float>(i), 0.0f})
.set<Velocity>({0.5f, 0.5f});
}
// Create movement system
world.system<Position, Velocity>("MoveSystem")
.each([](flecs::entity e, Position& p, Velocity& v) {
p.x += v.x;
p.y += v.y;
std::cout << "Entity " << e.name() << " moved to ("
<< p.x << ", " << p.y << ")" << std::endl;
});
// Run system
for (int i = 0; i < 3; ++i) {
std::cout << "Frame " << (i + 1) << ":" << std::endl;
world.progress();
}
return 0;
}
2. Queries and Filters
#include <flecs.h>
void query_example() {
flecs::world world;
// Register components
world.component<Position>();
world.component<Velocity>();
world.component<Health>();
// Create some test entities
world.entity("Player1")
.set<Position>({0, 0})
.set<Velocity>({1, 0})
.set<Health>({100, 100});
world.entity("Player2")
.set<Position>({5, 5})
.set<Health>({80, 100});
world.entity("Enemy1")
.set<Position>({10, 10})
.set<Velocity>({-1, 0});
// Create query: find all entities with Position and Velocity
auto moving_query = world.query<Position, Velocity>();
std::cout << "Moving entities:" << std::endl;
moving_query.each([](flecs::entity e, Position& p, Velocity& v) {
std::cout << " - " << e.name() << " at (" << p.x << ", " << p.y << ")" << std::endl;
});
// Create filter: find entities with Position but without Velocity
auto static_filter = world.filter_builder<Position>()
.without<Velocity>()
.build();
std::cout << "Static entities:" << std::endl;
static_filter.each([](flecs::entity e, Position& p) {
std::cout << " - " << e.name() << " at (" << p.x << ", " << p.y << ")" << std::endl;
});
}
💡 Practical Application Examples
1. Game Character System
#include <flecs.h>
#include <string>
// Game component definitions
struct Transform {
float x, y, z;
float rotation;
};
struct Sprite {
std::string texture_path;
int width, height;
};
struct PhysicsBody {
float velocity_x, velocity_y;
float acceleration;
bool on_ground;
};
struct PlayerController {
float move_speed;
float jump_force;
};
struct EnemyAI {
enum class State { PATROL, CHASE, ATTACK };
State current_state;
float detection_range;
};
class GameWorld {
private:
flecs::world world_;
public:
GameWorld() {
setup_components();
setup_systems();
create_entities();
}
void setup_components() {
world_.component<Transform>();
world_.component<Sprite>();
world_.component<PhysicsBody>();
world_.component<PlayerController>();
world_.component<EnemyAI>();
}
void setup_systems() {
// Physics system
world_.system<Transform, PhysicsBody>("PhysicsSystem")
.each([](flecs::entity e, Transform& t, PhysicsBody& pb) {
// Apply velocity
t.x += pb.velocity_x;
t.y += pb.velocity_y;
// Simple gravity simulation
if (!pb.on_ground) {
pb.velocity_y -= 9.8f * 0.016f; // Assume 60fps
}
// Ground detection (simplified)
if (t.y <= 0) {
t.y = 0;
pb.on_ground = true;
pb.velocity_y = 0;
} else {
pb.on_ground = false;
}
});
// Player input system
world_.system<PhysicsBody, PlayerController>("InputSystem")
.each([](flecs::entity e, PhysicsBody& pb, PlayerController& pc) {
// Here you can integrate actual input handling
// Simplified example: assume input
bool move_left = false;
bool move_right = true;
bool jump = false;
if (move_left) pb.velocity_x = -pc.move_speed;
if (move_right) pb.velocity_x = pc.move_speed;
if (!move_left && !move_right) pb.velocity_x = 0;
if (jump && pb.on_ground) {
pb.velocity_y = pc.jump_force;
pb.on_ground = false;
}
});
// Enemy AI system
world_.system<Transform, EnemyAI>("AISystem")
.each([](flecs::entity e, Transform& t, EnemyAI& ai) {
// Simplified AI logic
switch (ai.current_state) {
case EnemyAI::State::PATROL:
// Patrol logic
break;
case EnemyAI::State::CHASE:
// Chase player logic
break;
case EnemyAI::State::ATTACK:
// Attack logic
break;
}
});
// Render system (pseudo code)
world_.system<Transform, Sprite>("RenderSystem")
.each([](flecs::entity e, Transform& t, Sprite& s) {
// Here you would call graphics API to render sprite
std::cout << "Rendering " << s.texture_path
<< " at (" << t.x << ", " << t.y << ")" << std::endl;
});
}
void create_entities() {
// Create player
world_.entity("Player")
.set<Transform>({0, 0, 0, 0})
.set<Sprite>({"player.png", 32, 64})
.set<PhysicsBody>({0, 0, 0, true})
.set<PlayerController>({5.0f, 10.0f});
// Create enemies
world_.entity("Enemy1")
.set<Transform>({10, 0, 0, 0})
.set<Sprite>({"enemy.png", 32, 32})
.set<PhysicsBody>({0, 0, 0, true})
.set<EnemyAI>({EnemyAI::State::PATROL, 8.0f});
world_.entity("Enemy2")
.set<Transform>({20, 0, 0, 0})
.set<Sprite>({"enemy.png", 32, 32})
.set<PhysicsBody>({0, 0, 0, true})
.set<EnemyAI>({EnemyAI::State::PATROL, 8.0f});
}
void update(float delta_time) {
world_.set_target_fps(60);
world_.progress();
}
void run() {
// Simple game loop
for (int i = 0; i < 100; ++i) {
update(0.016f); // Assume 60fps
}
}
};
2. Relational ECS
#include <flecs.h>
void relationship_example() {
flecs::world world;
// Define relationship tags
auto IsParentOf = world.entity("IsParentOf");
auto IsChildOf = world.entity("IsChildOf");
auto IsFriendOf = world.entity("IsFriendOf");
// Create entities and establish relationships
auto parent = world.entity("Parent");
auto child1 = world.entity("Child1");
auto child2 = world.entity("Child2");
auto friend_entity = world.entity("Friend");
// Add relationships
parent.add(IsParentOf, child1);
parent.add(IsParentOf, child2);
child1.add(IsFriendOf, friend_entity);
// Query relationships
auto children_query = world.query_builder()
.with(IsChildOf, flecs::Wildcard) // Find all entities with IsChildOf relationship
.build();
std::cout << "Children found:" << std::endl;
children_query.each([](flecs::entity e) {
std::cout << " - " << e.name() << std::endl;
});
// Iterate over targets of specific relationship
auto parent_of = world.target(parent, IsParentOf);
std::cout << "Parent's children:" << std::endl;
parent_of.each([](flecs::entity e) {
std::cout << " - " << e.name() << std::endl;
});
}
🔧 Advanced Features and Module System
1. Custom Modules
#include <flecs.h>
// Define game-specific module
struct GameModule {
GameModule(flecs::world& world) {
world.module<GameModule>();
// Register components and systems in the module
world.component<Transform>();
world.component<Sprite>();
setup_systems(world);
}
static void setup_systems(flecs::world& world) {
world.system<Transform>("UpdateTransforms")
.each([](flecs::entity e, Transform& t) {
// Transform update logic
});
}
};
// Using the module
int main() {
flecs::world world;
// Import module
world.import<GameModule>();
// Now you can use components and systems defined in the module
world.entity("TestEntity")
.set<Transform>({0, 0, 0, 0});
world.progress();
return 0;
}
2. Serialization and Snapshots
#include <flecs.h>
void snapshot_example() {
flecs::world world;
world.component<Position>();
world.component<Velocity>();
// Create some test entities
for (int i = 0; i < 3; ++i) {
world.entity()
.set<Position>({static_cast<float>(i), static_cast<float>(i)})
.set<Velocity>({1.0f, 1.0f});
}
// Create world snapshot
flecs::snapshot snapshot(world);
snapshot.take();
// Modify original world
world.entity("NewEntity")
.set<Position>({99, 99});
// Restore snapshot
snapshot.restore();
std::cout << "World after restore:" << std::endl;
world.each([](flecs::entity e) {
std::cout << " - " << e.name() << std::endl;
});
}
💡 Performance Optimization Tips
- Batch Processing:
// Use each method for batch processing components world.system<Position, Velocity>("OptimizedSystem") .each([](flecs::entity e, Position& p, Velocity& v) { // This callback will be executed in batches, cache-friendly p.x += v.x; p.y += v.y; });
// Use iter method for finer control
world.system<Position, Velocity>(“AdvancedSystem”)
.iter([](flecs::iter& it, Position<em> p, Velocity<em> v) {
for (auto i : it) {
p[i].x += v[i].x;
p[i].y += v[i].y;
}
});
2. **Component Layout Optimization**:
```cpp
// Use SoA (Structure of Arrays) layout
struct OptimizedComponents {
struct Positions {
float x[1000];
float y[1000];
};
struct Velocities {
float x[1000];
float y[1000];
};
};
🔍 Suitable Scenarios
Flecs is particularly suitable for the following scenarios:
- Game Development: 2D/3D game engines, entity management systems
- Simulation Systems: Physics simulation, AI systems, economic simulations
- Visualization Tools: Data visualization, editor tools
- Real-time Systems: Applications requiring high performance and predictability
Flecs provides excellent framework support for building complex real-time applications through its powerful ECS implementation and rich feature set.