From cc4f83a1d172906e91e6c988bcc11797da3ae1f8 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 10 Oct 2024 17:34:33 -0400 Subject: [PATCH] Just wrote my own entity system to figure it out. --- gui.cpp | 8 +-- map.cpp | 11 ++-- meson.build | 8 ++- rand.cpp | 10 +-- rand.hpp | 24 +++++++- scratchpad/flecs.cpp | 39 ------------ scratchpad/flecstest.cpp | 61 +++++++++++++++++++ scratchpad/myecstest.cpp | 127 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 229 insertions(+), 59 deletions(-) delete mode 100644 scratchpad/flecs.cpp create mode 100644 scratchpad/flecstest.cpp create mode 100644 scratchpad/myecstest.cpp diff --git a/gui.cpp b/gui.cpp index aa91313..11fb77b 100644 --- a/gui.cpp +++ b/gui.cpp @@ -168,8 +168,8 @@ void GUI::handle_events() { void GUI::burn() { for(int i = 0; i < 20; ++i) { $map_text.setFillColor(color(i % VALUES.size())); - int x = Random::rand_int(-10,10); - int y = Random::rand_int(-10,10); + int x = Random::uniform(-10,10); + int y = Random::uniform(-10,10); draw_screen(false, x, y); std::this_thread::sleep_for(2ms); } @@ -187,8 +187,8 @@ void GUI::draw_screen(bool clear, float map_off_x, float map_off_y) { void GUI::shake() { for(int i = 0; i < 10; ++i) { - int x = Random::rand_int(-10,10); - int y = Random::rand_int(-10,10); + int x = Random::uniform(-10,10); + int y = Random::uniform(-10,10); // add x/y back to draw screen draw_screen(true, x, y); std::this_thread::sleep_for(1ms); diff --git a/map.cpp b/map.cpp index 90138ec..d055bc9 100644 --- a/map.cpp +++ b/map.cpp @@ -115,7 +115,7 @@ inline int make_split(Room &cur, bool horiz) { int min = dimension / 4; int max = dimension - min; - return Random::rand_int(min, max); + return Random::uniform(min, max); } void Map::partition_map(Room &cur, int depth) { @@ -125,7 +125,6 @@ void Map::partition_map(Room &cur, int depth) { return; } - std::uniform_int_distribution rsplit(0, 1); bool horiz = cur.width > cur.height ? false : true; int split = make_split(cur, horiz); Room left = cur; @@ -210,10 +209,10 @@ void Map::set_door(Room &room, int value) { } void rand_side(Room &room, Point &door) { - int rand_x = Random::rand_int(0, room.width - 1); - int rand_y = Random::rand_int(0, room.height - 1); + int rand_x = Random::uniform(0, room.width - 1); + int rand_y = Random::uniform(0, room.height - 1); - switch(Random::rand_int(0,3)) { + switch(Random::uniform(0,3)) { case 0: // north door.x = room.x + rand_x; door.y = room.y-1; @@ -306,7 +305,7 @@ void Map::generate() { println("ROOM NOT FOUND!"); } clear_target(target.entry); - } + } Room &src = $rooms.back(); Room &target = $rooms.front(); diff --git a/meson.build b/meson.build index f240aed..383594f 100644 --- a/meson.build +++ b/meson.build @@ -35,10 +35,14 @@ roguish = executable('roguish', [ ], dependencies: dependencies) -runtests = executable('flecstest', [ - './scratchpad/flecs.cpp' +flectest = executable('flecstest', [ + './scratchpad/flecstest.cpp' ], dependencies: dependencies) +myecstest = executable('myecstest', [ + './scratchpad/myecstest.cpp' + ], + dependencies: dependencies) test('tests', runtests) diff --git a/rand.cpp b/rand.cpp index 7c7a833..25d77d7 100644 --- a/rand.cpp +++ b/rand.cpp @@ -1,10 +1,6 @@ #include "rand.hpp" -std::random_device RNG; -std::mt19937 GENERATOR(RNG()); - -int Random::rand_int(int from, int to) { - std::uniform_int_distribution rand(from, to); - - return rand(GENERATOR); +namespace Random { + std::random_device RNG; + std::mt19937 GENERATOR(RNG()); } diff --git a/rand.hpp b/rand.hpp index b5e3031..359c2b5 100644 --- a/rand.hpp +++ b/rand.hpp @@ -1,6 +1,28 @@ #pragma once #include + namespace Random { - int rand_int(int from, int to); + extern std::mt19937 GENERATOR; + + template + T uniform(T from, T to) { + std::uniform_int_distribution rand(from, to); + + return rand(GENERATOR); + } + + template + T uniform_real(T from, T to) { + std::uniform_real_distribution rand(from, to); + + return rand(GENERATOR); + } + + template + T normal(T from, T to) { + std::normal_distribution rand(from, to); + + return rand(GENERATOR); + } } diff --git a/scratchpad/flecs.cpp b/scratchpad/flecs.cpp deleted file mode 100644 index ab20b8e..0000000 --- a/scratchpad/flecs.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -struct Position { - double x, y; -}; - -struct Velocity { - double x, y; -}; - -int main() { - flecs::world ecs; - - // Create a system for Position, Velocity. Systems are like queries (see - // queries) with a function that can be ran or scheduled (see pipeline). - flecs::system s = ecs.system() - .each([](flecs::entity e, Position& p, const Velocity& v) { - p.x += v.x; - p.y += v.y; - std::cerr << e.name() << ": {" << p.x << ", " << p.y << "}\n"; - }); - - // Create a few test entities for a Position, Velocity query - ecs.entity("e1") - .set({10, 20}) - .set({1, 2}); - - ecs.entity("e2") - .set({10, 20}) - .set({3, 4}); - - // This entity will not match as it does not have Position, Velocity - ecs.entity("e3") - .set({10, 20}); - - // Run the system - s.run(); -} diff --git a/scratchpad/flecstest.cpp b/scratchpad/flecstest.cpp new file mode 100644 index 0000000..fe10dd2 --- /dev/null +++ b/scratchpad/flecstest.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +struct Position { + double x, y; +}; + +struct Velocity { + double x, y; +}; + +int main() { + flecs::world ecs; + + flecs::system fight = ecs.system() + .each([&](flecs::entity e, const Position &other) { + flecs::entity player = ecs.lookup("player"); + if(e == player) return; // don't process the player + + const Position *player_p = player.get(); + if(player_p->x == other.x && player_p->y == other.y) { + std::cerr << "HIT\n"; + } + }); + + // Create a system for Position, Velocity. Systems are like queries (see + // queries) with a function that can be ran or scheduled (see pipeline). + flecs::system move = ecs.system() + .each([&](flecs::entity e, Position& p, const Velocity& v) { + p.x += v.x; + p.y += v.y; + std::cerr << e.name() << ": {" << p.x << ", " << p.y << "}\n"; + }); + + // Create a few test entities for a Position, Velocity query + ecs.entity("player") + .set({10, 10}) + .set({1, 1}); + + ecs.entity("e2") + .set({10, 20}) + .set({1, 1}); + + // This entity will not match as it does not have Position, Velocity + ecs.entity("e3") + .set({10, 20}); + + std::unordered_map type_names; + type_names[std::type_index(typeid(Position))] = "Position"; + type_names[std::type_index(typeid(Velocity))] = "Velocity"; + + for(const auto& [key, value] : type_names) { + std::cout << " VAL " << value << std::endl; + } + // Run the system + move.run(); + fight.run(); +} diff --git a/scratchpad/myecstest.cpp b/scratchpad/myecstest.cpp new file mode 100644 index 0000000..395678f --- /dev/null +++ b/scratchpad/myecstest.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace fmt; + +struct Position { + double x, y; +}; + +struct Velocity { + double x, y; +}; + +typedef unsigned long Entity; + +typedef std::unordered_map EntityMap; + +struct World { + unsigned long entity_count = 0; + std::unordered_map $components; + + Entity entity() { + return ++entity_count; + } + + template + EntityMap& entity_map_for() { + return $components[std::type_index(typeid(Comp))]; + } + + 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(); + std::any &res = map[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); + } + } + } +}; + +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("--- Query only entities with Position and Velocity:"); + 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); + }); + + // 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); + }); + + return 0; +}