📦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);
|
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();
|
entity_id make_entity();
|
||||||
void destroy_entity(entity_id e);
|
void destroy_entity(entity_id e);
|
||||||
bool is_alive(entity_id e) const;
|
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>
|
template<Component T>
|
||||||
bool has(entity_id e) const;
|
bool has(entity_id e) const;
|
||||||
|
@ -66,12 +74,18 @@ namespace zecsy
|
||||||
template<Component... T>
|
template<Component... T>
|
||||||
void query(std::invocable<entity_id, T&...> auto&& system);
|
void query(std::invocable<entity_id, T&...> auto&& system);
|
||||||
|
|
||||||
|
size_t get_archetypes_checked() const;
|
||||||
|
size_t get_entities_processed() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using comp_id = size_t;
|
using comp_id = size_t;
|
||||||
std::set<entity_id> alive_entities;
|
std::set<entity_id> alive_entities;
|
||||||
std::unordered_map<entity_id, std::set<comp_id>> entity_to_comps;
|
std::unordered_map<entity_id, std::set<comp_id>> entity_to_comps;
|
||||||
entity_id entity_counter = 0;
|
entity_id entity_counter = 0;
|
||||||
|
|
||||||
|
size_t query_archetypes_checked = 0;
|
||||||
|
size_t query_entities_processed = 0;
|
||||||
|
|
||||||
struct component_pool
|
struct component_pool
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
@ -119,6 +133,51 @@ namespace zecsy
|
||||||
|
|
||||||
inline world::comp_id world::next_component_id = 0;
|
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()
|
inline entity_id world::make_entity()
|
||||||
{
|
{
|
||||||
auto id = ++entity_counter;
|
auto id = ++entity_counter;
|
||||||
|
@ -305,8 +364,13 @@ namespace zecsy
|
||||||
std::vector<comp_id> required = {get_component_id<T>()...};
|
std::vector<comp_id> required = {get_component_id<T>()...};
|
||||||
std::sort(required.begin(), required.end());
|
std::sort(required.begin(), required.end());
|
||||||
|
|
||||||
|
query_archetypes_checked = 0;
|
||||||
|
query_entities_processed = 0;
|
||||||
|
|
||||||
for(const auto& [archetype_key, entities]: archetypes)
|
for(const auto& [archetype_key, entities]: archetypes)
|
||||||
{
|
{
|
||||||
|
query_archetypes_checked++;
|
||||||
|
|
||||||
bool match = true;
|
bool match = true;
|
||||||
for(comp_id req_id: required)
|
for(comp_id req_id: required)
|
||||||
{
|
{
|
||||||
|
@ -320,6 +384,7 @@ namespace zecsy
|
||||||
|
|
||||||
if(match)
|
if(match)
|
||||||
{
|
{
|
||||||
|
query_entities_processed += entities.size();
|
||||||
for(entity_id e: entities)
|
for(entity_id e: entities)
|
||||||
{
|
{
|
||||||
system(e, get<T>(e)...);
|
system(e, get<T>(e)...);
|
||||||
|
|
Loading…
Reference in a new issue