Store components in vector

This commit is contained in:
NukeBird 2025-02-13 22:25:18 +03:00
parent 336e5a5733
commit 5665b1de6e
2 changed files with 63 additions and 12 deletions

View file

@ -13,7 +13,14 @@ namespace DinkyECS
{ {
typedef unsigned long Entity; typedef unsigned long Entity;
using EntityMap = std::unordered_map<Entity, std::any>; using EntityMap = std::unordered_map<Entity, size_t>;
template <typename T>
struct ComponentStorage
{
std::vector<T> data;
std::queue<size_t> free_indices;
};
struct Event struct Event
{ {
@ -30,6 +37,7 @@ struct World
std::unordered_map<std::type_index, EntityMap> $components; std::unordered_map<std::type_index, EntityMap> $components;
std::unordered_map<std::type_index, std::any> $facts; std::unordered_map<std::type_index, std::any> $facts;
std::unordered_map<std::type_index, EventQueue> $events; std::unordered_map<std::type_index, EventQueue> $events;
std::unordered_map<std::type_index, std::any> $component_storages;
std::vector<Entity> $constants; std::vector<Entity> $constants;
Entity entity() { return ++entity_count; } Entity entity() { return ++entity_count; }
@ -58,6 +66,35 @@ struct World
$constants.push_back(entity); $constants.push_back(entity);
} }
template <typename Comp>
size_t make_component()
{
auto &storage = component_storage_for<Comp>();
size_t index;
if (!storage.free_indices.empty())
{
index = storage.free_indices.front();
storage.free_indices.pop();
}
else
{
storage.data.emplace_back();
index = storage.data.size() - 1;
}
return index;
}
template <typename Comp>
ComponentStorage<Comp> &component_storage_for()
{
auto type_index = std::type_index(typeid(Comp));
$component_storages.try_emplace(type_index, ComponentStorage<Comp>{});
return std::any_cast<ComponentStorage<Comp> &>(
$component_storages.at(type_index));
}
template <typename Comp> template <typename Comp>
EntityMap &entity_map_for() EntityMap &entity_map_for()
{ {
@ -74,6 +111,13 @@ struct World
void remove(Entity ent) void remove(Entity ent)
{ {
EntityMap &map = entity_map_for<Comp>(); EntityMap &map = entity_map_for<Comp>();
if (map.contains(ent))
{
size_t index = map.at(ent);
component_storage_for<Comp>().free_indices.push(index);
}
map.erase(ent); map.erase(ent);
} }
@ -108,16 +152,24 @@ struct World
void set(Entity ent, Comp val) void set(Entity ent, Comp val)
{ {
EntityMap &map = entity_map_for<Comp>(); EntityMap &map = entity_map_for<Comp>();
map.insert_or_assign(ent, val);
if (has<Comp>(ent))
{
get<Comp>(ent) = val;
return;
}
map.insert_or_assign(ent, make_component<Comp>());
get<Comp>(ent) = val;
} }
template <typename Comp> template <typename Comp>
Comp &get(Entity ent) Comp &get(Entity ent)
{ {
EntityMap &map = entity_map_for<Comp>(); EntityMap &map = entity_map_for<Comp>();
// use .at for bounds checking auto &storage = component_storage_for<Comp>();
std::any &res = map.at(ent); auto index = map.at(ent);
return std::any_cast<Comp &>(res); return storage.data[index];
} }
template <typename Comp> template <typename Comp>
@ -131,10 +183,10 @@ struct World
void query(std::function<void(const Entity &, Comp &)> cb) void query(std::function<void(const Entity &, Comp &)> cb)
{ {
EntityMap &map = entity_map_for<Comp>(); EntityMap &map = entity_map_for<Comp>();
for (auto &[entity, any_comp] : map)
for (auto &[entity, index] : map)
{ {
Comp &res = std::any_cast<Comp &>(any_comp); cb(entity, get<Comp>(entity));
cb(entity, res);
} }
} }
@ -144,13 +196,11 @@ struct World
EntityMap &map_a = entity_map_for<CompA>(); EntityMap &map_a = entity_map_for<CompA>();
EntityMap &map_b = entity_map_for<CompB>(); EntityMap &map_b = entity_map_for<CompB>();
for (auto &[entity, any_a] : map_a) for (auto &[entity, index_a] : map_a)
{ {
if (map_b.contains(entity)) if (map_b.contains(entity))
{ {
CompA &res_a = std::any_cast<CompA &>(any_a); cb(entity, get<CompA>(entity), get<CompB>(entity));
CompB &res_b = get<CompB>(entity);
cb(entity, res_a, res_b);
} }
} }
} }

View file

@ -1,6 +1,7 @@
#include "dinkyecs.hpp" #include "dinkyecs.hpp"
#include "point.hpp" #include "point.hpp"
#include <cassert> #include <cassert>
#include <fmt/base.h>
#define REQUIRE(X) assert(X); #define REQUIRE(X) assert(X);