Bye-bye entity wrapper
This commit is contained in:
parent
12f2bf3474
commit
3b8234655d
2 changed files with 46 additions and 125 deletions
|
@ -15,7 +15,6 @@ TEST_CASE("Create a single entity and verify its existence")
|
||||||
auto e = w.make_entity();
|
auto e = w.make_entity();
|
||||||
|
|
||||||
REQUIRE(w.is_alive(e));
|
REQUIRE(w.is_alive(e));
|
||||||
REQUIRE(e.is_alive());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Destroy an entity and ensure it no longer exists in the world")
|
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);
|
w.destroy_entity(e);
|
||||||
|
|
||||||
REQUIRE_FALSE(w.is_alive(e));
|
REQUIRE_FALSE(w.is_alive(e));
|
||||||
REQUIRE_FALSE(e.is_alive());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Entity #0 should be reserved and never used")
|
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();
|
auto e = w.make_entity();
|
||||||
|
|
||||||
REQUIRE(e != 0);
|
REQUIRE(e != 0);
|
||||||
REQUIRE(entity() == 0);
|
REQUIRE_FALSE(w.is_alive(0));
|
||||||
REQUIRE_FALSE(entity().is_alive());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChoosenOne
|
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();
|
auto e = w.make_entity();
|
||||||
|
|
||||||
REQUIRE_FALSE(w.has<ChoosenOne>(e));
|
REQUIRE_FALSE(w.has<ChoosenOne>(e));
|
||||||
REQUIRE_FALSE(e.has<ChoosenOne>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Attempt of getting non-owned component should throw")
|
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();
|
auto e = w.make_entity();
|
||||||
|
|
||||||
REQUIRE_THROWS(w.get<ChoosenOne>(e));
|
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")
|
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;
|
world w;
|
||||||
|
|
||||||
auto e1 = w.make_entity();
|
auto e1 = w.make_entity();
|
||||||
e1.set(ChoosenOne{});
|
w.set(e1, ChoosenOne{});
|
||||||
|
|
||||||
REQUIRE(e1.has<ChoosenOne>());
|
|
||||||
REQUIRE(w.has<ChoosenOne>(e1));
|
REQUIRE(w.has<ChoosenOne>(e1));
|
||||||
|
|
||||||
auto e2 = w.make_entity();
|
auto e2 = w.make_entity();
|
||||||
w.set(e2, ChoosenOne{});
|
w.set(e2, ChoosenOne{});
|
||||||
|
|
||||||
REQUIRE(e2.has<ChoosenOne>());
|
|
||||||
REQUIRE(w.has<ChoosenOne>(e2));
|
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;
|
world w;
|
||||||
|
|
||||||
auto e = w.make_entity();
|
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")
|
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;
|
world w;
|
||||||
|
|
||||||
auto e = w.make_entity();
|
auto e = w.make_entity();
|
||||||
e.set(ChoosenOne{});
|
w.set(e, ChoosenOne{});
|
||||||
REQUIRE_NOTHROW(e.remove<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_NOTHROW(w.remove<ChoosenOne>(e));
|
||||||
|
|
||||||
REQUIRE_FALSE(w.has<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")
|
TEST_CASE("Addresses of removed components should be reused")
|
||||||
{
|
{
|
||||||
world w;
|
world w;
|
||||||
std::vector<entity> entities;
|
std::vector<entity_id> entities;
|
||||||
std::vector<ChoosenOne*> addr;
|
std::vector<ChoosenOne*> addr;
|
||||||
|
|
||||||
const int N = 4;
|
const int N = 4;
|
||||||
|
@ -130,27 +123,27 @@ TEST_CASE("Addresses of removed components should be reused")
|
||||||
for(int j = 0; j < N; ++j)
|
for(int j = 0; j < N; ++j)
|
||||||
{
|
{
|
||||||
entities.emplace_back(w.make_entity());
|
entities.emplace_back(w.make_entity());
|
||||||
entities.back().set<ChoosenOne>();
|
w.set<ChoosenOne>(entities.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr.empty())
|
if(addr.empty())
|
||||||
{
|
{
|
||||||
for(int j = 0; j < N; ++j)
|
for(int j = 0; j < N; ++j)
|
||||||
{
|
{
|
||||||
addr.emplace_back(&entities[j].get<ChoosenOne>());
|
addr.emplace_back(&w.get<ChoosenOne>(entities[j]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(int j = 0; j < N; ++j)
|
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)
|
for(auto e: entities)
|
||||||
{
|
{
|
||||||
e.remove<ChoosenOne>();
|
w.remove<ChoosenOne>(e);
|
||||||
}
|
}
|
||||||
entities.clear();
|
entities.clear();
|
||||||
}
|
}
|
||||||
|
@ -161,17 +154,15 @@ TEST_CASE("Attach multiple components to an entity and verify all are correctly
|
||||||
world w;
|
world w;
|
||||||
|
|
||||||
auto e = w.make_entity();
|
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));
|
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(w.has<ChoosenOne, Name>(e));
|
||||||
REQUIRE_FALSE(e.has<ChoosenOne>());
|
REQUIRE_FALSE(w.has<ChoosenOne>(e));
|
||||||
REQUIRE_FALSE(e.has<Name>());
|
REQUIRE_FALSE(w.has<Name>(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Create a simple system that processes entities with a specific component and verify it executes correctly")
|
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;
|
world w;
|
||||||
auto e0 = w.make_entity(), e1 = w.make_entity();
|
auto e0 = w.make_entity(), e1 = w.make_entity();
|
||||||
|
|
||||||
e0.set<Component>(); //or e0.set(Component{})
|
w.set<Component>(e0); //or e0.set(Component{})
|
||||||
e1.set(Component{20});
|
w.set(e1, Component{20});
|
||||||
|
|
||||||
REQUIRE(e0.get<Component>().value == 0);
|
REQUIRE(w.get<Component>(e0).value == 0);
|
||||||
REQUIRE(e1.get<Component>().value == 20);
|
REQUIRE(w.get<Component>(e1).value == 20);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Really wanna deduce it to w.query([](Component&){}),
|
* 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++;
|
c.value++;
|
||||||
});
|
});
|
||||||
|
|
||||||
REQUIRE(e0.get<Component>().value == 1);
|
REQUIRE(w.get<Component>(e0).value == 1);
|
||||||
REQUIRE(e1.get<Component>().value == 21);
|
REQUIRE(w.get<Component>(e1).value == 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test a system’s ability to query and process only entities with a specific combination of components")
|
TEST_CASE("Test a system’s ability to query and process only entities with a specific combination of components")
|
||||||
|
@ -218,18 +209,18 @@ TEST_CASE("Test a system’s ability to query and process only entities with a s
|
||||||
world w;
|
world w;
|
||||||
|
|
||||||
auto e0 = w.make_entity();
|
auto e0 = w.make_entity();
|
||||||
e0.set(C0{}, C1{});
|
w.set(e0, C0{}, C1{});
|
||||||
|
|
||||||
auto e1 = w.make_entity();
|
auto e1 = w.make_entity();
|
||||||
e1.set(C0{});
|
w.set(e1, C0{});
|
||||||
|
|
||||||
auto e2 = w.make_entity();
|
auto e2 = w.make_entity();
|
||||||
e2.set(C1{});
|
w.set(e2, C1{});
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
REQUIRE(e0.get<C0>().value == 0);
|
REQUIRE(w.get<C0>(e0).value == 0);
|
||||||
REQUIRE(e0.get<C1>().value == 10);
|
REQUIRE(w.get<C1>(e0).value == 10);
|
||||||
|
|
||||||
w.query<C0, C1>([&count](C0& c0, C1& c1)
|
w.query<C0, C1>([&count](C0& c0, C1& c1)
|
||||||
{
|
{
|
||||||
|
@ -237,12 +228,12 @@ TEST_CASE("Test a system’s ability to query and process only entities with a s
|
||||||
c1.value++;
|
c1.value++;
|
||||||
});
|
});
|
||||||
|
|
||||||
REQUIRE(e0.get<C0>().value == 1);
|
REQUIRE(w.get<C0>(e0).value == 1);
|
||||||
REQUIRE(e0.get<C1>().value == 11);
|
REQUIRE(w.get<C1>(e0).value == 11);
|
||||||
|
|
||||||
REQUIRE(e1.get<C0>().value == 0);
|
REQUIRE(w.get<C0>(e1).value == 0);
|
||||||
REQUIRE(e2.get<C1>().value == 10);
|
REQUIRE(w.get<C1>(e2).value == 10);
|
||||||
|
|
||||||
REQUIRE_FALSE(e1.has<C1>());
|
REQUIRE_FALSE(w.has<C1>(e1));
|
||||||
REQUIRE_FALSE(e2.has<C0>());
|
REQUIRE_FALSE(w.has<C0>(e2));
|
||||||
}
|
}
|
||||||
|
|
90
zecsy.hpp
90
zecsy.hpp
|
@ -1,8 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <catch2/internal/catch_console_colour.hpp>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <functional>
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
@ -22,36 +20,7 @@ namespace zecsy
|
||||||
*/
|
*/
|
||||||
using entities_set = std::set<entity_id>;
|
using entities_set = std::set<entity_id>;
|
||||||
|
|
||||||
class entity final
|
class component_storage 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
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -104,7 +73,7 @@ namespace zecsy
|
||||||
class world final
|
class world final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
entity 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;
|
||||||
|
|
||||||
|
@ -131,27 +100,12 @@ namespace zecsy
|
||||||
component_storage storage;
|
component_storage storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline entity::entity(class world* w, entity_id id): w(w), id(id)
|
inline entity_id world::make_entity()
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
auto id = ++entity_counter;
|
auto id = ++entity_counter;
|
||||||
alive_entities.emplace(id);
|
alive_entities.emplace(id);
|
||||||
|
|
||||||
return entity(this, id);
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void world::destroy_entity(entity_id e)
|
inline void world::destroy_entity(entity_id e)
|
||||||
|
@ -191,30 +145,12 @@ namespace zecsy
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... T>
|
|
||||||
inline bool entity::has() const
|
|
||||||
{
|
|
||||||
return w->has<T...>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T& world::get(entity_id e)
|
inline T& world::get(entity_id e)
|
||||||
{
|
{
|
||||||
return storage.get<T>(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>
|
template<typename T>
|
||||||
inline void component_storage::set(entity_id e, const T& comp)
|
inline void component_storage::set(entity_id e, const T& comp)
|
||||||
{
|
{
|
||||||
|
@ -246,6 +182,12 @@ namespace zecsy
|
||||||
indices_dict[typeid(T)][e] = index;
|
indices_dict[typeid(T)][e] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void component_storage::set(entity_id e)
|
||||||
|
{
|
||||||
|
set(e, T{});
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
inline void world::set(entity_id e)
|
inline void world::set(entity_id e)
|
||||||
{
|
{
|
||||||
|
@ -258,12 +200,6 @@ namespace zecsy
|
||||||
storage.set(e, comps...);
|
storage.set(e, comps...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... T>
|
|
||||||
inline void entity::set(const T&... comps)
|
|
||||||
{
|
|
||||||
w->set(id, comps...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void component_storage::remove(entity_id e)
|
inline void component_storage::remove(entity_id e)
|
||||||
{
|
{
|
||||||
|
@ -283,12 +219,6 @@ namespace zecsy
|
||||||
storage.remove<T...>(e);
|
storage.remove<T...>(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... T>
|
|
||||||
inline void entity::remove()
|
|
||||||
{
|
|
||||||
w->remove<T...>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
inline bool world::has(entity_id e) const
|
inline bool world::has(entity_id e) const
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue