diff --git a/ecs.hpp b/ecs.hpp index 6f05bb5..45cfecc 100644 --- a/ecs.hpp +++ b/ecs.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -226,6 +227,16 @@ namespace ecs_hpp template < typename T > const T* find_component() const noexcept; + + template < typename... Ts > + std::tuple get_components(); + template < typename... Ts > + std::tuple get_components() const; + + template < typename... Ts > + std::tuple find_components() noexcept; + template < typename... Ts > + std::tuple find_components() const noexcept; private: world& owner_; entity_id id_{0u}; @@ -285,6 +296,16 @@ namespace ecs_hpp template < typename T > const T* find_component(const entity& ent) const noexcept; + template < typename... Ts > + std::tuple get_components(const entity& ent); + template < typename... Ts > + std::tuple get_components(const entity& ent) const; + + template < typename... Ts > + std::tuple find_components(const entity& ent) noexcept; + template < typename... Ts > + std::tuple find_components(const entity& ent) const noexcept; + template < typename T, typename F > void for_each_component(F&& f); template < typename T, typename F > @@ -363,7 +384,7 @@ namespace ecs_hpp } inline bool entity::is_alive() const noexcept { - return owner_.is_entity_alive(*this); + return const_cast(owner_).is_entity_alive(*this); } template < typename T, typename... Args > @@ -380,7 +401,7 @@ namespace ecs_hpp template < typename T > bool entity::exists_component() const noexcept { - return owner_.exists_component(*this); + return const_cast(owner_).exists_component(*this); } inline std::size_t entity::remove_all_components() noexcept { @@ -394,7 +415,7 @@ namespace ecs_hpp template < typename T > const T& entity::get_component() const { - return owner_.get_component(*this); + return const_cast(owner_).get_component(*this); } template < typename T > @@ -404,7 +425,27 @@ namespace ecs_hpp template < typename T > const T* entity::find_component() const noexcept { - return owner_.find_component(*this); + return const_cast(owner_).find_component(*this); + } + + template < typename... Ts > + std::tuple entity::get_components() { + return owner_.get_components(*this); + } + + template < typename... Ts > + std::tuple entity::get_components() const { + return const_cast(owner_).get_components(*this); + } + + template < typename... Ts > + std::tuple entity::find_components() noexcept { + return owner_.find_components(*this); + } + + template < typename... Ts > + std::tuple entity::find_components() const noexcept { + return const_cast(owner_).find_components(*this); } inline bool operator==(const entity& l, const entity& r) noexcept { @@ -520,6 +561,26 @@ namespace ecs_hpp return find_component_impl_(ent); } + template < typename... Ts > + std::tuple world::get_components(const entity& ent) { + return std::make_tuple(std::ref(get_component(ent))...); + } + + template < typename... Ts > + std::tuple world::get_components(const entity& ent) const { + return std::make_tuple(std::cref(get_component(ent))...); + } + + template < typename... Ts > + std::tuple world::find_components(const entity& ent) noexcept { + return std::make_tuple(find_component(ent)...); + } + + template < typename... Ts > + std::tuple world::find_components(const entity& ent) const noexcept { + return std::make_tuple(find_component(ent)...); + } + template < typename T, typename F > void world::for_each_component(F&& f) { std::lock_guard guard(mutex_); diff --git a/ecs_tests.cpp b/ecs_tests.cpp index d4efab9..480db43 100644 --- a/ecs_tests.cpp +++ b/ecs_tests.cpp @@ -27,6 +27,16 @@ namespace velocity_c() = default; velocity_c(int nx, int ny) : x(nx), y(ny) {} }; + + bool operator==(const position_c& l, const position_c& r) noexcept { + return l.x == r.x + && l.y == r.y; + } + + bool operator==(const velocity_c& l, const velocity_c& r) noexcept { + return l.x == r.x + && l.y == r.y; + } } TEST_CASE("detail") { @@ -202,6 +212,75 @@ TEST_CASE("world") { REQUIRE_FALSE(ww.find_component(e2)); } } + { + ecs::world w; + + auto e1 = w.create_entity(); + + REQUIRE(e1.find_components<>() == + std::make_tuple()); + REQUIRE(e1.find_components() == + std::make_tuple(nullptr)); + REQUIRE(e1.find_components() == + std::make_tuple(nullptr, nullptr)); + + REQUIRE(e1.get_components<>() == std::make_tuple()); + REQUIRE_THROWS(e1.get_components()); + REQUIRE_THROWS(e1.get_components()); + + { + const auto ee1 = e1; + + REQUIRE(ee1.find_components<>() == + std::make_tuple()); + REQUIRE(ee1.find_components() == + std::make_tuple(nullptr)); + REQUIRE(ee1.find_components() == + std::make_tuple(nullptr, nullptr)); + + REQUIRE(ee1.get_components<>() == std::make_tuple()); + REQUIRE_THROWS(ee1.get_components()); + REQUIRE_THROWS(ee1.get_components()); + } + + e1.assign_component(3, 4); + + REQUIRE(e1.find_components() == + std::make_tuple(e1.find_component())); + REQUIRE(e1.find_components() == + std::make_tuple(nullptr, e1.find_component())); + + REQUIRE(e1.get_components() == + std::make_tuple(e1.get_component())); + REQUIRE_THROWS(e1.get_components()); + + { + const auto ee1 = e1; + + REQUIRE(ee1.find_components() == + std::make_tuple(e1.find_component())); + REQUIRE(ee1.find_components() == + std::make_tuple(nullptr, e1.find_component())); + + REQUIRE(ee1.get_components() == + std::make_tuple(ee1.get_component())); + REQUIRE_THROWS(ee1.get_components()); + } + + e1.assign_component(1, 2); + + auto p = e1.get_components(); + std::get<0>(p).x = 10; + std::get<1>(p).x = 30; + REQUIRE(e1.get_component().x == 10); + REQUIRE(e1.get_component().x == 30); + + auto p2 = e1.find_components(); + std::get<0>(p2)->y = 20; + std::get<1>(p2)->y = 40; + REQUIRE(e1.get_component().y == 20); + REQUIRE(e1.get_component().y == 40); + } } SECTION("for_each_component") { {