Bye-bye entity wrapper

This commit is contained in:
NukeBird 2025-02-15 22:33:02 +03:00
parent 12f2bf3474
commit 3b8234655d
2 changed files with 46 additions and 125 deletions

View file

@ -15,7 +15,6 @@ TEST_CASE("Create a single entity and verify its existence")
auto e = w.make_entity();
REQUIRE(w.is_alive(e));
REQUIRE(e.is_alive());
}
TEST_CASE("Destroy an entity and ensure it no longer exists in the world")
@ -26,7 +25,6 @@ TEST_CASE("Destroy an entity and ensure it no longer exists in the world")
w.destroy_entity(e);
REQUIRE_FALSE(w.is_alive(e));
REQUIRE_FALSE(e.is_alive());
}
TEST_CASE("Entity #0 should be reserved and never used")
@ -36,8 +34,7 @@ TEST_CASE("Entity #0 should be reserved and never used")
auto e = w.make_entity();
REQUIRE(e != 0);
REQUIRE(entity() == 0);
REQUIRE_FALSE(entity().is_alive());
REQUIRE_FALSE(w.is_alive(0));
}
struct ChoosenOne
@ -52,7 +49,6 @@ TEST_CASE("Entity shouldn't have a component that wasn't attached to it")
auto e = w.make_entity();
REQUIRE_FALSE(w.has<ChoosenOne>(e));
REQUIRE_FALSE(e.has<ChoosenOne>());
}
TEST_CASE("Attempt of getting non-owned component should throw")
@ -62,7 +58,6 @@ TEST_CASE("Attempt of getting non-owned component should throw")
auto e = w.make_entity();
REQUIRE_THROWS(w.get<ChoosenOne>(e));
REQUIRE_THROWS(e.get<ChoosenOne>());
}
TEST_CASE("Attach a simple component to an entity and verify it is correctly associated")
@ -70,15 +65,13 @@ TEST_CASE("Attach a simple component to an entity and verify it is correctly ass
world w;
auto e1 = w.make_entity();
e1.set(ChoosenOne{});
w.set(e1, ChoosenOne{});
REQUIRE(e1.has<ChoosenOne>());
REQUIRE(w.has<ChoosenOne>(e1));
auto e2 = w.make_entity();
w.set(e2, ChoosenOne{});
REQUIRE(e2.has<ChoosenOne>());
REQUIRE(w.has<ChoosenOne>(e2));
}
@ -92,13 +85,13 @@ TEST_CASE("Retrieve a component from an entity and verify its data matches what
world w;
auto e = w.make_entity();
e.set(Name{"zecsy!"});
w.set(e, Name{"zecsy!"});
REQUIRE(e.get<Name>().value == "zecsy!");
REQUIRE(w.get<Name>(e).value == "zecsy!");
e.get<Name>().value = "super-zecsy!";
w.get<Name>(e).value = "super-zecsy!";
REQUIRE(e.get<Name>().value == "super-zecsy!");
REQUIRE(w.get<Name>(e).value == "super-zecsy!");
}
TEST_CASE("Remove a component from an entity and verify it is no longer attached")
@ -106,12 +99,12 @@ TEST_CASE("Remove a component from an entity and verify it is no longer attached
world w;
auto e = w.make_entity();
e.set(ChoosenOne{});
REQUIRE_NOTHROW(e.remove<ChoosenOne>());
w.set(e, ChoosenOne{});
REQUIRE_NOTHROW(w.remove<ChoosenOne>(e));
REQUIRE_FALSE(e.has<ChoosenOne>());
REQUIRE_FALSE(w.has<ChoosenOne>(e));
e.set(ChoosenOne{});
w.set(e, ChoosenOne{});
REQUIRE_NOTHROW(w.remove<ChoosenOne>(e));
REQUIRE_FALSE(w.has<ChoosenOne>(e));
@ -120,7 +113,7 @@ TEST_CASE("Remove a component from an entity and verify it is no longer attached
TEST_CASE("Addresses of removed components should be reused")
{
world w;
std::vector<entity> entities;
std::vector<entity_id> entities;
std::vector<ChoosenOne*> addr;
const int N = 4;
@ -130,27 +123,27 @@ TEST_CASE("Addresses of removed components should be reused")
for(int j = 0; j < N; ++j)
{
entities.emplace_back(w.make_entity());
entities.back().set<ChoosenOne>();
w.set<ChoosenOne>(entities.back());
}
if(addr.empty())
{
for(int j = 0; j < N; ++j)
{
addr.emplace_back(&entities[j].get<ChoosenOne>());
addr.emplace_back(&w.get<ChoosenOne>(entities[j]));
}
}
else
{
for(int j = 0; j < N; ++j)
{
REQUIRE(&entities[j].get<ChoosenOne>() == addr[j]);
REQUIRE(&w.get<ChoosenOne>(entities[j]) == addr[j]);
}
}
for(auto e: entities)
{
e.remove<ChoosenOne>();
w.remove<ChoosenOne>(e);
}
entities.clear();
}
@ -161,17 +154,15 @@ TEST_CASE("Attach multiple components to an entity and verify all are correctly
world w;
auto e = w.make_entity();
e.set(ChoosenOne{}, Name{"zecsy"});
w.set(e, ChoosenOne{}, Name{"zecsy"});
REQUIRE(e.has<ChoosenOne, Name>());
REQUIRE(w.has<ChoosenOne, Name>(e));
e.remove<ChoosenOne, Name>();
w.remove<ChoosenOne, Name>(e);
REQUIRE_FALSE(e.has<ChoosenOne, Name>());
REQUIRE_FALSE(w.has<ChoosenOne, Name>(e));
REQUIRE_FALSE(e.has<ChoosenOne>());
REQUIRE_FALSE(e.has<Name>());
REQUIRE_FALSE(w.has<ChoosenOne>(e));
REQUIRE_FALSE(w.has<Name>(e));
}
TEST_CASE("Create a simple system that processes entities with a specific component and verify it executes correctly")
@ -184,11 +175,11 @@ TEST_CASE("Create a simple system that processes entities with a specific compon
world w;
auto e0 = w.make_entity(), e1 = w.make_entity();
e0.set<Component>(); //or e0.set(Component{})
e1.set(Component{20});
w.set<Component>(e0); //or e0.set(Component{})
w.set(e1, Component{20});
REQUIRE(e0.get<Component>().value == 0);
REQUIRE(e1.get<Component>().value == 20);
REQUIRE(w.get<Component>(e0).value == 0);
REQUIRE(w.get<Component>(e1).value == 20);
/*
* Really wanna deduce it to w.query([](Component&){}),
@ -199,8 +190,8 @@ TEST_CASE("Create a simple system that processes entities with a specific compon
c.value++;
});
REQUIRE(e0.get<Component>().value == 1);
REQUIRE(e1.get<Component>().value == 21);
REQUIRE(w.get<Component>(e0).value == 1);
REQUIRE(w.get<Component>(e1).value == 21);
}
TEST_CASE("Test a systems ability to query and process only entities with a specific combination of components")
@ -218,18 +209,18 @@ TEST_CASE("Test a systems ability to query and process only entities with a s
world w;
auto e0 = w.make_entity();
e0.set(C0{}, C1{});
w.set(e0, C0{}, C1{});
auto e1 = w.make_entity();
e1.set(C0{});
w.set(e1, C0{});
auto e2 = w.make_entity();
e2.set(C1{});
w.set(e2, C1{});
int count = 0;
REQUIRE(e0.get<C0>().value == 0);
REQUIRE(e0.get<C1>().value == 10);
REQUIRE(w.get<C0>(e0).value == 0);
REQUIRE(w.get<C1>(e0).value == 10);
w.query<C0, C1>([&count](C0& c0, C1& c1)
{
@ -237,12 +228,12 @@ TEST_CASE("Test a systems ability to query and process only entities with a s
c1.value++;
});
REQUIRE(e0.get<C0>().value == 1);
REQUIRE(e0.get<C1>().value == 11);
REQUIRE(w.get<C0>(e0).value == 1);
REQUIRE(w.get<C1>(e0).value == 11);
REQUIRE(e1.get<C0>().value == 0);
REQUIRE(e2.get<C1>().value == 10);
REQUIRE(w.get<C0>(e1).value == 0);
REQUIRE(w.get<C1>(e2).value == 10);
REQUIRE_FALSE(e1.has<C1>());
REQUIRE_FALSE(e2.has<C0>());
REQUIRE_FALSE(w.has<C1>(e1));
REQUIRE_FALSE(w.has<C0>(e2));
}

View file

@ -1,8 +1,6 @@
#pragma once
#include <catch2/internal/catch_console_colour.hpp>
#include <cstdint>
#include <format>
#include <functional>
#include <queue>
#include <stdexcept>
#include <typeindex>
@ -22,36 +20,7 @@ namespace zecsy
*/
using entities_set = std::set<entity_id>;
class entity final
{
public:
entity(class world* w, entity_id id);
entity() = default;
operator entity_id() const;
bool is_alive() const;
template<typename... T>
bool has() const;
template<typename T>
T& get();
template<typename... T>
void set();
template<typename... T>
void set(const T&... comps);
template<typename... T>
void remove();
private:
entity_id id = 0;
class world* w = nullptr;
};
class component_storage
class component_storage final
{
public:
template<typename T>
@ -104,7 +73,7 @@ namespace zecsy
class world final
{
public:
entity make_entity();
entity_id make_entity();
void destroy_entity(entity_id e);
bool is_alive(entity_id e) const;
@ -131,27 +100,12 @@ namespace zecsy
component_storage storage;
};
inline entity::entity(class world* w, entity_id id): w(w), id(id)
{
}
inline entity::operator entity_id() const
{
return id;
}
inline bool entity::is_alive() const
{
return w && w->is_alive(id);
}
inline entity world::make_entity()
inline entity_id world::make_entity()
{
auto id = ++entity_counter;
alive_entities.emplace(id);
return entity(this, id);
return id;
}
inline void world::destroy_entity(entity_id e)
@ -191,30 +145,12 @@ namespace zecsy
return *ptr;
}
template<typename... T>
inline bool entity::has() const
{
return w->has<T...>(id);
}
template<typename T>
inline T& world::get(entity_id e)
{
return storage.get<T>(e);
}
template<typename T>
inline T& entity::get()
{
return w->get<T>(id);
}
template<typename... T>
inline void entity::set()
{
(set(T{}), ...);
}
template<typename T>
inline void component_storage::set(entity_id e, const T& comp)
{
@ -246,6 +182,12 @@ namespace zecsy
indices_dict[typeid(T)][e] = index;
}
template<typename T>
inline void component_storage::set(entity_id e)
{
set(e, T{});
}
template<typename... T>
inline void world::set(entity_id e)
{
@ -258,12 +200,6 @@ namespace zecsy
storage.set(e, comps...);
}
template<typename... T>
inline void entity::set(const T&... comps)
{
w->set(id, comps...);
}
template<typename T>
inline void component_storage::remove(entity_id e)
{
@ -283,12 +219,6 @@ namespace zecsy
storage.remove<T...>(e);
}
template<typename... T>
inline void entity::remove()
{
w->remove<T...>(id);
}
template<typename... T>
inline bool world::has(entity_id e) const
{