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;
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
{
@ -30,6 +37,7 @@ struct World
std::unordered_map<std::type_index, EntityMap> $components;
std::unordered_map<std::type_index, std::any> $facts;
std::unordered_map<std::type_index, EventQueue> $events;
std::unordered_map<std::type_index, std::any> $component_storages;
std::vector<Entity> $constants;
Entity entity() { return ++entity_count; }
@ -58,6 +66,35 @@ struct World
$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>
EntityMap &entity_map_for()
{
@ -74,6 +111,13 @@ struct World
void remove(Entity ent)
{
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);
}
@ -108,16 +152,24 @@ struct World
void set(Entity ent, Comp val)
{
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>
Comp &get(Entity ent)
{
EntityMap &map = entity_map_for<Comp>();
// use .at for bounds checking
std::any &res = map.at(ent);
return std::any_cast<Comp &>(res);
auto &storage = component_storage_for<Comp>();
auto index = map.at(ent);
return storage.data[index];
}
template <typename Comp>
@ -131,10 +183,10 @@ struct World
void query(std::function<void(const Entity &, Comp &)> cb)
{
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, res);
cb(entity, get<Comp>(entity));
}
}
@ -144,13 +196,11 @@ struct World
EntityMap &map_a = entity_map_for<CompA>();
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))
{
CompA &res_a = std::any_cast<CompA &>(any_a);
CompB &res_b = get<CompB>(entity);
cb(entity, res_a, res_b);
cb(entity, get<CompA>(entity), get<CompB>(entity));
}
}
}

View file

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