#include #include #include #include #include #include #include using namespace fmt; typedef unsigned long Entity; typedef std::unordered_map EntityMap; struct World { unsigned long entity_count = 0; std::unordered_map $components; std::unordered_map $facts; Entity entity() { return ++entity_count; } template EntityMap& entity_map_for() { return $components[std::type_index(typeid(Comp))]; } template void set(Comp val) { $facts[std::type_index(typeid(Comp))] = val; } template Comp &get() { // use .at to get std::out_of_range if fact not set std::any &res = $facts.at(std::type_index(typeid(Comp))); return std::any_cast(res); } template void assign(Entity ent, Comp val) { EntityMap &map = entity_map_for(); map[ent] = val; } template Comp &component(Entity ent) { EntityMap &map = entity_map_for(); // use .at for bounds checking std::any &res = map.at(ent); return std::any_cast(res); } template void system(std::function cb) { EntityMap &map = entity_map_for(); for(auto& [entity, any_comp] : map) { Comp &res = std::any_cast(any_comp); cb(entity, res); } } template void remove(Entity ent) { EntityMap &map = entity_map_for(); map.erase(ent); } template void system(std::function cb) { EntityMap &map_a = entity_map_for(); EntityMap &map_b = entity_map_for(); for(auto& [entity, any_a] : map_a) { if(map_b.contains(entity)) { CompA &res_a = std::any_cast(any_a); CompB &res_b = component(entity); cb(entity, res_a, res_b); } } } template std::function runner(std::function cb) { return [&]{ system(cb); }; } }; struct Position { double x, y; }; struct Velocity { double x, y; }; struct Gravity { double level; }; int main() { World me; Entity test = me.entity(); Entity test2 = me.entity(); me.assign(test, {10,20}); me.assign(test, {1,2}); me.assign(test2, {1,1}); me.assign(test2, {10,20}); Position &pos = me.component(test); println("GOT POS x={}, y={}", pos.x, pos.y); Velocity &vel = me.component(test); println("GOT VELOCITY x={}, y={}", vel.x, vel.y); println("--- Position only system:"); me.system([](const auto &ent, auto &pos) { println("entity={}, pos.x={}, pos.y={}", ent, pos.x, pos.y); }); println("--- Velocity only system:"); me.system([](const auto &, auto &vel) { println("vel.x={}, vel.y={}", vel.x, vel.y); }); println("--- Manually get the velocity in position system:"); me.system([&](const auto &ent, auto &pos) { Velocity &vel = me.component(ent); println("entity={}, vel.x, vel.y, pos.x={}, pos.y={}", ent, vel.x, vel.y, pos.x, pos.y); }); println("--- Creating facts (singletons)"); me.set({0.9}); println("--- Query only entities with Position and Velocity:"); me.system([&](const auto &ent, auto &pos, auto &vel) { Gravity &grav = me.get(); println("grav={}, entity={}, vel.x, vel.y, pos.x={}, pos.y={}", grav.level, ent, vel.x, vel.y, pos.x, pos.y); }); // now remove Velocity me.remove(test); println("--- After remove test, should only result in test2:"); me.system([&](const auto &ent, auto &pos, auto &vel) { println("entity={}, vel.x, vel.y, pos.x={}, pos.y={}", ent, vel.x, vel.y, pos.x, pos.y); }); println("--- Create a stored system you can save for later."); auto movementSystem = me.runner([&](const auto &ent, auto &pos, auto &vel) { println("entity={}, vel.x, vel.y, pos.x={}, pos.y={}", ent, vel.x, vel.y, pos.x, pos.y); }); movementSystem(); return 0; }