a tiny, ergonomic header-only ecs in modern c++.
first built as part of a learning project, now powering two of my games.
consider using flecs or EnTT first.
#include <klecs.h>
struct Transform {
int position[3];
};
struct Rigidbody {
int linear_velocity[3];
};
int main() {
klecs::World world{};
world.spawn(Transform{.position = {0, 0, 0}}, Rigidbody{.linear_velocity = {1, 0, 0}});
world.query<Transform &, Rigidbody &>(
[](const EntityId &id, Transform &transform, const Rigidbody &rigidbody) {
transform.position[0] += rigidbody.linear_velocity[0];
transform.position[1] += rigidbody.linear_velocity[1];
transform.position[2] += rigidbody.linear_velocity[2];
});
return 0;
}
#include <klecs.h>
int main() {
klecs::World world{};
klecs::EntityId id = world.spawn(0);
world.remove(id);
return 0;
}
#include <klecs.h>
int main() {
klecs::World world{};
world.spawn(0); // Id: 1
world.spawn(0, 0.0f); // Id: 2
world.clear_exact<int>(); // clears 1, but leaves 2 intact because signature doesn't fully match
world.clear_exact<int, float>(); // clears 2, but leaves 1 intact
world.clear_matching<int>(); // clears both 1 and 2
return 0;
}
#include <klecs.h>
int main() {
klecs::World world{};
klecs::EntityId id = world.spawn(0, 0.0f, 'c');
std::optional<std::tuple<int, float&>> components = world.get<int, float&>(id);
if (!components.has_value()) {
// world.get returns nullopt if we requested a component this entity does not have
// for example: world.get<double>(id);
return 1;
}
float& float_ref = std::get<float&>(*components);
float_ref = 1.0f;
return 0;
}
useful for nested queries, i.e. simple collision checks.
#include <iostream>
#include <klecs.h>
int main() {
klecs::World world{};
world.spawn(0);
world.spawn(1);
world.spawn(2);
world.spawn(3);
std::vector<std::tuple<int>> numbers = world.query_into_vec<int>();
for (auto& number : numbers) {
std::cout << std::get<int>(number) << ", "; // 1, 2, 3, 4,
}
return 0;
}
useful for checking if entities with certain components still exist.
#include <klecs.h>
int main() {
klecs::World world{};
world.spawn(0, 'c');
world.spawn(0.0f, 'a');
world.spawn(5, 't');
world.spawn(1.0, 's');
world.query_count<char>(); // -> 4
return 0;
}