📦Archetypes, entities, components introspection📦
This commit is contained in:
parent
8055ac0cac
commit
cb05c2cf1d
2 changed files with 198 additions and 0 deletions
133
tests/zecsy.cpp
133
tests/zecsy.cpp
|
@ -409,3 +409,136 @@ TEST_CASE("Systems handle negative delta time")
|
|||
|
||||
REQUIRE(count == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Entity count tracking")
|
||||
{
|
||||
world w;
|
||||
REQUIRE(w.entity_count() == 0);
|
||||
|
||||
const auto e1 = w.make_entity();
|
||||
const auto e2 = w.make_entity();
|
||||
REQUIRE(w.entity_count() == 2);
|
||||
|
||||
w.destroy_entity(e1);
|
||||
REQUIRE(w.entity_count() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Component counting mechanisms")
|
||||
{
|
||||
struct Health
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
struct Position
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
world w;
|
||||
auto e = w.make_entity();
|
||||
|
||||
REQUIRE(w.component_count<Health>() == 0);
|
||||
REQUIRE(w.total_component_count() == 0);
|
||||
|
||||
w.set<Health>(e);
|
||||
REQUIRE(w.component_count<Health>() == 1);
|
||||
REQUIRE(w.total_component_count() == 1);
|
||||
|
||||
w.set<Position>(e);
|
||||
REQUIRE(w.component_count<Position>() == 1);
|
||||
REQUIRE(w.total_component_count() == 2);
|
||||
|
||||
w.remove<Health>(e);
|
||||
REQUIRE(w.component_count<Health>() == 0);
|
||||
REQUIRE(w.total_component_count() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Archetype signature management")
|
||||
{
|
||||
struct A
|
||||
{
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
};
|
||||
|
||||
world w;
|
||||
|
||||
// Initial state: empty archetype
|
||||
REQUIRE(w.archetype_count() == 0);
|
||||
|
||||
auto e = w.make_entity();
|
||||
REQUIRE(w.archetype_count() == 1);
|
||||
|
||||
// Add first component
|
||||
w.set<A>(e);
|
||||
REQUIRE(w.archetype_count() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Component distribution across archetypes")
|
||||
{
|
||||
struct A
|
||||
{
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
};
|
||||
|
||||
world w;
|
||||
|
||||
// Create 10 entities in different configurations
|
||||
for(int i = 0; i < 5; ++i)
|
||||
{
|
||||
auto e = w.make_entity();
|
||||
w.set<A>(e);
|
||||
}
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
auto e = w.make_entity();
|
||||
w.set<A, B>(e);
|
||||
}
|
||||
for(int i = 0; i < 2; ++i)
|
||||
{
|
||||
auto e = w.make_entity();
|
||||
w.set<B>(e);
|
||||
}
|
||||
|
||||
// Verify distribution
|
||||
REQUIRE(w.entity_count() == 10);
|
||||
REQUIRE(w.component_count<A>() == 8);
|
||||
REQUIRE(w.component_count<B>() == 5);
|
||||
REQUIRE(w.archetype_count() == 3); //<A>, <A, B>, <B>
|
||||
}
|
||||
|
||||
TEST_CASE("Entity inspection")
|
||||
{
|
||||
struct Transform
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct Renderable
|
||||
{
|
||||
};
|
||||
|
||||
world w;
|
||||
auto e = w.make_entity();
|
||||
|
||||
REQUIRE(w.components_in_entity(e) == 0);
|
||||
|
||||
w.set<Transform>(e);
|
||||
REQUIRE(w.components_in_entity(e) == 1);
|
||||
|
||||
w.set<Renderable>(e);
|
||||
REQUIRE(w.components_in_entity(e) == 2);
|
||||
|
||||
w.remove<Transform>(e);
|
||||
REQUIRE(w.components_in_entity(e) == 1);
|
||||
}
|
||||
|
|
65
zecsy.hpp
65
zecsy.hpp
|
@ -34,6 +34,14 @@ namespace zecsy
|
|||
entity_id make_entity();
|
||||
void destroy_entity(entity_id e);
|
||||
bool is_alive(entity_id e) const;
|
||||
size_t components_in_entity(entity_id e) const;
|
||||
|
||||
size_t entity_count() const;
|
||||
size_t total_component_count() const;
|
||||
size_t archetype_count() const;
|
||||
|
||||
template<Component T>
|
||||
size_t component_count();
|
||||
|
||||
template<Component T>
|
||||
bool has(entity_id e) const;
|
||||
|
@ -66,12 +74,18 @@ namespace zecsy
|
|||
template<Component... T>
|
||||
void query(std::invocable<entity_id, T&...> auto&& system);
|
||||
|
||||
size_t get_archetypes_checked() const;
|
||||
size_t get_entities_processed() const;
|
||||
|
||||
private:
|
||||
using comp_id = size_t;
|
||||
std::set<entity_id> alive_entities;
|
||||
std::unordered_map<entity_id, std::set<comp_id>> entity_to_comps;
|
||||
entity_id entity_counter = 0;
|
||||
|
||||
size_t query_archetypes_checked = 0;
|
||||
size_t query_entities_processed = 0;
|
||||
|
||||
struct component_pool
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
|
@ -119,6 +133,51 @@ namespace zecsy
|
|||
|
||||
inline world::comp_id world::next_component_id = 0;
|
||||
|
||||
inline size_t world::components_in_entity(entity_id e) const
|
||||
{
|
||||
return entity_to_comps.contains(e) ? entity_to_comps.at(e).size() : 0;
|
||||
}
|
||||
|
||||
inline size_t world::entity_count() const
|
||||
{
|
||||
return alive_entities.size();
|
||||
}
|
||||
|
||||
inline size_t world::total_component_count() const
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
for(const auto& [id, pool]: pools)
|
||||
{
|
||||
count += pool.entity_to_index.size();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
inline size_t world::archetype_count() const
|
||||
{
|
||||
return archetypes.size();
|
||||
}
|
||||
|
||||
template<Component T>
|
||||
inline size_t world::component_count()
|
||||
{
|
||||
const comp_id id = get_component_id<T>();
|
||||
const auto it = pools.find(id);
|
||||
return it != pools.end() ? it->second.entity_to_index.size() : 0;
|
||||
}
|
||||
|
||||
inline size_t world::get_archetypes_checked() const
|
||||
{
|
||||
return query_archetypes_checked;
|
||||
}
|
||||
|
||||
inline size_t world::get_entities_processed() const
|
||||
{
|
||||
return query_entities_processed;
|
||||
}
|
||||
|
||||
inline entity_id world::make_entity()
|
||||
{
|
||||
auto id = ++entity_counter;
|
||||
|
@ -305,8 +364,13 @@ namespace zecsy
|
|||
std::vector<comp_id> required = {get_component_id<T>()...};
|
||||
std::sort(required.begin(), required.end());
|
||||
|
||||
query_archetypes_checked = 0;
|
||||
query_entities_processed = 0;
|
||||
|
||||
for(const auto& [archetype_key, entities]: archetypes)
|
||||
{
|
||||
query_archetypes_checked++;
|
||||
|
||||
bool match = true;
|
||||
for(comp_id req_id: required)
|
||||
{
|
||||
|
@ -320,6 +384,7 @@ namespace zecsy
|
|||
|
||||
if(match)
|
||||
{
|
||||
query_entities_processed += entities.size();
|
||||
for(entity_id e: entities)
|
||||
{
|
||||
system(e, get<T>(e)...);
|
||||
|
|
Loading…
Reference in a new issue