diff --git a/README.md b/README.md index 5000e63..650f93b 100644 --- a/README.md +++ b/README.md @@ -35,15 +35,15 @@ ```cpp struct position_component { - float x{0}; - float y{0}; + float x; + float y; position_component(float nx, float ny) : x(nx), y(ny) {} }; struct velocity_component { - float dx{0}; - float dy{0}; + float dx; + float dy; velocity_component(float ndx, float ndy) : dx(ndx), dy(ndy) {} }; diff --git a/ecs.hpp b/ecs.hpp index 7618284..c2180a3 100644 --- a/ecs.hpp +++ b/ecs.hpp @@ -74,6 +74,14 @@ namespace ecs_hpp return t; } + // + // hash_combine + // + + constexpr std::size_t hash_combine(std::size_t l, std::size_t r) noexcept { + return l ^ (r + 0x9e3779b9 + (l << 6) + (l >> 2)); + } + // // tuple_tail // @@ -189,7 +197,7 @@ namespace ecs_hpp }; template < typename T > - class type_family : public type_family_base<> { + class type_family final : public type_family_base<> { public: static family_id id() noexcept { static family_id self_id = ++last_id_; @@ -226,7 +234,7 @@ namespace ecs_hpp struct sparse_unsigned_indexer {}; template < typename T > - struct sparse_indexer + struct sparse_indexer final : public sparse_unsigned_indexer {}; } } @@ -466,7 +474,9 @@ namespace ecs_hpp std::enable_if_t< std::is_nothrow_move_assignable::value, bool> - unordered_erase(const K& k) { + unordered_erase(const K& k) + noexcept(std::is_nothrow_move_assignable::value) + { if ( !keys_.has(k) ) { return false; } @@ -532,7 +542,7 @@ namespace ecs_hpp { namespace detail { - struct entity_id_indexer { + struct entity_id_indexer final { std::size_t operator()(entity_id id) const noexcept { return entity_id_index(id); } @@ -554,21 +564,25 @@ namespace ecs_hpp public: virtual ~component_storage_base() = default; virtual bool remove(entity_id id) noexcept = 0; - virtual bool exists(entity_id id) const noexcept = 0; + virtual bool has(entity_id id) const noexcept = 0; }; template < typename T > - class component_storage : public component_storage_base { + class component_storage final : public component_storage_base { public: component_storage(registry& owner); template < typename... Args > void assign(entity_id id, Args&&... args); + bool exists(entity_id id) const noexcept; bool remove(entity_id id) noexcept override; - bool exists(entity_id id) const noexcept override; + T* find(entity_id id) noexcept; const T* find(entity_id id) const noexcept; + std::size_t count() const noexcept; + bool has(entity_id id) const noexcept override; + template < typename F > void for_each_component(F&& f) noexcept; template < typename F > @@ -591,13 +605,13 @@ namespace ecs_hpp } template < typename T > - bool component_storage::remove(entity_id id) noexcept { - return components_.unordered_erase(id); + bool component_storage::exists(entity_id id) const noexcept { + return components_.has(id); } template < typename T > - bool component_storage::exists(entity_id id) const noexcept { - return components_.has(id); + bool component_storage::remove(entity_id id) noexcept { + return components_.unordered_erase(id); } template < typename T > @@ -610,11 +624,21 @@ namespace ecs_hpp return components_.find(id); } + template < typename T > + std::size_t component_storage::count() const noexcept { + return components_.size(); + } + + template < typename T > + bool component_storage::has(entity_id id) const noexcept { + return components_.has(id); + } + template < typename T > template < typename F > void component_storage::for_each_component(F&& f) noexcept { for ( const auto id : components_ ) { - f(entity(owner_, id), components_.get(id)); + f(id, components_.get(id)); } } @@ -622,7 +646,7 @@ namespace ecs_hpp template < typename F > void component_storage::for_each_component(F&& f) const noexcept { for ( const auto id : components_ ) { - f(const_entity(owner_, id), components_.get(id)); + f(id, components_.get(id)); } } } @@ -641,11 +665,13 @@ namespace ecs_hpp entity(registry& owner) noexcept; entity(registry& owner, entity_id id) noexcept; + registry& owner() noexcept; const registry& owner() const noexcept; + entity_id id() const noexcept; bool destroy(); - bool is_alive() const noexcept; + bool alive() const noexcept; template < typename T, typename... Args > bool assign_component(Args&&... args); @@ -680,7 +706,7 @@ namespace ecs_hpp template < typename... Ts > std::tuple find_components() const noexcept; private: - registry* owner_; + registry* owner_{nullptr}; entity_id id_{0u}; }; @@ -691,11 +717,13 @@ namespace ecs_hpp namespace std { template <> - struct hash + struct hash final : std::unary_function { std::size_t operator()(const ecs_hpp::entity& ent) const noexcept { - return std::hash()(ent.id()); + return ecs_hpp::detail::hash_combine( + std::hash()(&ent.owner()), + std::hash()(ent.id())); } }; } @@ -718,7 +746,7 @@ namespace ecs_hpp const registry& owner() const noexcept; entity_id id() const noexcept; - bool is_alive() const noexcept; + bool alive() const noexcept; template < typename T > bool exists_component() const noexcept; @@ -735,7 +763,7 @@ namespace ecs_hpp template < typename... Ts > std::tuple find_components() const noexcept; private: - const registry* owner_; + const registry* owner_{nullptr}; entity_id id_{0u}; }; @@ -746,11 +774,13 @@ namespace ecs_hpp namespace std { template <> - struct hash + struct hash final : std::unary_function { std::size_t operator()(const ecs_hpp::const_entity& ent) const noexcept { - return std::hash()(ent.id()); + return ecs_hpp::detail::hash_combine( + std::hash()(&ent.owner()), + std::hash()(ent.id())); } }; } @@ -779,44 +809,92 @@ namespace ecs_hpp namespace ecs_hpp { class registry final { + private: + class uentity { + public: + uentity(registry& owner, entity_id id) noexcept; + + uentity(entity_id ent) noexcept; + uentity(entity ent) noexcept; + + operator entity_id() const noexcept; + operator entity() const noexcept; + operator const_entity() const noexcept; + + entity_id id() const noexcept; + registry* owner() noexcept; + const registry* owner() const noexcept; + + bool check_owner(const registry* owner) const noexcept; + private: + entity_id id_{0u}; + registry* owner_{nullptr}; + }; + + class const_uentity { + public: + const_uentity(const registry& owner, entity_id id) noexcept; + + const_uentity(entity_id ent) noexcept; + const_uentity(entity ent) noexcept; + const_uentity(const_entity ent) noexcept; + const_uentity(const uentity& ent) noexcept; + + operator entity_id() const noexcept; + operator const_entity() const noexcept; + + entity_id id() const noexcept; + const registry* owner() const noexcept; + + bool check_owner(const registry* owner) const noexcept; + private: + entity_id id_{0u}; + const registry* owner_{nullptr}; + }; public: registry() = default; ~registry() noexcept = default; entity create_entity(); - bool destroy_entity(const entity& ent); - bool is_entity_alive(const const_entity& ent) const noexcept; + + bool destroy_entity(const uentity& ent); + bool alive_entity(const const_uentity& ent) const noexcept; template < typename T, typename... Args > - bool assign_component(const entity& ent, Args&&... args); + bool assign_component(const uentity& ent, Args&&... args); template < typename T > - bool remove_component(const entity& ent); + bool remove_component(const uentity& ent); template < typename T > - bool exists_component(const const_entity& ent) const noexcept; + bool exists_component(const const_uentity& ent) const noexcept; - std::size_t remove_all_components(const entity& ent) noexcept; + std::size_t remove_all_components(const uentity& ent) noexcept; template < typename T > - T& get_component(const entity& ent); + T& get_component(const uentity& ent); template < typename T > - const T& get_component(const const_entity& ent) const; + const T& get_component(const const_uentity& ent) const; template < typename T > - T* find_component(const entity& ent) noexcept; + T* find_component(const uentity& ent) noexcept; template < typename T > - const T* find_component(const const_entity& ent) const noexcept; + const T* find_component(const const_uentity& ent) const noexcept; template < typename... Ts > - std::tuple get_components(const entity& ent); + std::tuple get_components(const uentity& ent); template < typename... Ts > - std::tuple get_components(const const_entity& ent) const; + std::tuple get_components(const const_uentity& ent) const; template < typename... Ts > - std::tuple find_components(const entity& ent) noexcept; + std::tuple find_components(const uentity& ent) noexcept; template < typename... Ts > - std::tuple find_components(const const_entity& ent) const noexcept; + std::tuple find_components(const const_uentity& ent) const noexcept; + + template < typename T > + std::size_t component_count() const noexcept; + template < typename T > + std::size_t entity_component_count(const const_uentity& ent) const noexcept; template < typename F > void for_each_entity(F&& f); @@ -839,25 +917,30 @@ namespace ecs_hpp private: template < typename T > detail::component_storage* find_storage_() noexcept; + template < typename T > const detail::component_storage* find_storage_() const noexcept; template < typename T > detail::component_storage& get_or_create_storage_(); - bool is_entity_alive_impl_(const const_entity& ent) const noexcept; - std::size_t remove_all_components_impl_(const entity& ent) noexcept; + template < typename T + , typename... Ts + , typename F + , std::size_t I + , std::size_t... Is > + void for_joined_components_impl_( + F&& f, + std::index_sequence iseq); - template < typename T > - T* find_component_impl_(const entity& ent) noexcept; - template < typename T > - const T* find_component_impl_(const const_entity& ent) const noexcept; - - template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is > - void for_joined_components_impl_(F&& f, std::index_sequence iseq); - - template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is > - void for_joined_components_impl_(F&& f, std::index_sequence iseq) const; + template < typename T + , typename... Ts + , typename F + , std::size_t I + , std::size_t... Is > + void for_joined_components_impl_( + F&& f, + std::index_sequence iseq) const; template < typename T , typename... Ts @@ -865,7 +948,7 @@ namespace ecs_hpp , typename Ss , typename... Cs > void for_joined_components_impl_( - const entity& e, + const uentity& e, const F& f, const Ss& ss, Cs&... cs); @@ -876,21 +959,21 @@ namespace ecs_hpp , typename Ss , typename... Cs > void for_joined_components_impl_( - const const_entity& e, + const const_uentity& e, const F& f, const Ss& ss, const Cs&... cs) const; template < typename F, typename... Cs > void for_joined_components_impl_( - const entity& e, + const uentity& e, const F& f, const std::tuple<>& ss, Cs&... cs); template < typename F, typename... Cs > void for_joined_components_impl_( - const const_entity& e, + const const_uentity& e, const F& f, const std::tuple<>& ss, const Cs&... cs) const; @@ -922,6 +1005,10 @@ namespace ecs_hpp : owner_(&owner) , id_(id) {} + inline registry& entity::owner() noexcept { + return *owner_; + } + inline const registry& entity::owner() const noexcept { return *owner_; } @@ -931,72 +1018,72 @@ namespace ecs_hpp } inline bool entity::destroy() { - return (*owner_).destroy_entity(*this); + return (*owner_).destroy_entity(id_); } - inline bool entity::is_alive() const noexcept { - return detail::as_const(*owner_).is_entity_alive(*this); + inline bool entity::alive() const noexcept { + return detail::as_const(*owner_).alive_entity(id_); } template < typename T, typename... Args > bool entity::assign_component(Args&&... args) { return (*owner_).assign_component( - *this, + id_, std::forward(args)...); } template < typename T > bool entity::remove_component() { - return (*owner_).remove_component(*this); + return (*owner_).remove_component(id_); } template < typename T > bool entity::exists_component() const noexcept { - return detail::as_const(*owner_).exists_component(*this); + return detail::as_const(*owner_).exists_component(id_); } inline std::size_t entity::remove_all_components() noexcept { - return (*owner_).remove_all_components(*this); + return (*owner_).remove_all_components(id_); } template < typename T > T& entity::get_component() { - return (*owner_).get_component(*this); + return (*owner_).get_component(id_); } template < typename T > const T& entity::get_component() const { - return detail::as_const(*owner_).get_component(*this); + return detail::as_const(*owner_).get_component(id_); } template < typename T > T* entity::find_component() noexcept { - return (*owner_).find_component(*this); + return (*owner_).find_component(id_); } template < typename T > const T* entity::find_component() const noexcept { - return detail::as_const(*owner_).find_component(*this); + return detail::as_const(*owner_).find_component(id_); } template < typename... Ts > std::tuple entity::get_components() { - return (*owner_).get_components(*this); + return (*owner_).get_components(id_); } template < typename... Ts > std::tuple entity::get_components() const { - return detail::as_const(*owner_).get_components(*this); + return detail::as_const(*owner_).get_components(id_); } template < typename... Ts > std::tuple entity::find_components() noexcept { - return (*owner_).find_components(*this); + return (*owner_).find_components(id_); } template < typename... Ts > std::tuple entity::find_components() const noexcept { - return detail::as_const(*owner_).find_components(*this); + return detail::as_const(*owner_).find_components(id_); } inline bool operator==(const entity& l, const entity& r) noexcept { @@ -1036,33 +1123,33 @@ namespace ecs_hpp return id_; } - inline bool const_entity::is_alive() const noexcept { - return (*owner_).is_entity_alive(*this); + inline bool const_entity::alive() const noexcept { + return (*owner_).alive_entity(id_); } template < typename T > bool const_entity::exists_component() const noexcept { - return (*owner_).exists_component(*this); + return (*owner_).exists_component(id_); } template < typename T > const T& const_entity::get_component() const { - return (*owner_).get_component(*this); + return (*owner_).get_component(id_); } template < typename T > const T* const_entity::find_component() const noexcept { - return (*owner_).find_component(*this); + return (*owner_).find_component(id_); } template < typename... Ts > std::tuple const_entity::get_components() const { - return (*owner_).get_components(*this); + return (*owner_).get_components(id_); } template < typename... Ts > std::tuple const_entity::find_components() const noexcept { - return (*owner_).find_components(*this); + return (*owner_).find_components(id_); } inline bool operator==(const const_entity& l, const const_entity& r) noexcept { @@ -1083,77 +1170,184 @@ namespace ecs_hpp namespace ecs_hpp { + // + // registry::uentity + // + + inline registry::uentity::uentity(registry& owner, entity_id id) noexcept + : id_(id) + , owner_(&owner) {} + + inline registry::uentity::uentity(entity_id ent) noexcept + : id_(ent) {} + + inline registry::uentity::uentity(entity ent) noexcept + : id_(ent.id()) + , owner_(&ent.owner()) {} + + inline registry::uentity::operator entity_id() const noexcept { + return id_; + } + + inline registry::uentity::operator entity() const noexcept { + assert(owner_); + return {*owner_, id_}; + } + + inline registry::uentity::operator const_entity() const noexcept { + assert(owner_); + return {*owner_, id_}; + } + + inline entity_id registry::uentity::id() const noexcept { + return id_; + } + + inline registry* registry::uentity::owner() noexcept { + return owner_; + } + + inline const registry* registry::uentity::owner() const noexcept { + return owner_; + } + + inline bool registry::uentity::check_owner(const registry* owner) const noexcept { + return !owner_ || owner_ == owner; + } + + // + // registry::const_uentity + // + + inline registry::const_uentity::const_uentity(const registry& owner, entity_id id) noexcept + : id_(id) + , owner_(&owner) {} + + inline registry::const_uentity::const_uentity(entity_id ent) noexcept + : id_(ent) {} + + inline registry::const_uentity::const_uentity(entity ent) noexcept + : id_(ent.id()) + , owner_(&ent.owner()) {} + + inline registry::const_uentity::const_uentity(const_entity ent) noexcept + : id_(ent.id()) + , owner_(&ent.owner()) {} + + inline registry::const_uentity::const_uentity(const uentity& ent) noexcept + : id_(ent.id()) + , owner_(ent.owner()) {} + + inline registry::const_uentity::operator entity_id() const noexcept { + return id_; + } + + inline registry::const_uentity::operator const_entity() const noexcept { + assert(owner_); + return {*owner_, id_}; + } + + inline entity_id registry::const_uentity::id() const noexcept { + return id_; + } + + inline const registry* registry::const_uentity::owner() const noexcept { + return owner_; + } + + inline bool registry::const_uentity::check_owner(const registry* owner) const noexcept { + return !owner_ || owner_ == owner; + } + + // + // registry + // + inline entity registry::create_entity() { if ( !free_entity_ids_.empty() ) { const auto free_ent_id = free_entity_ids_.back(); const auto new_ent_id = detail::upgrade_entity_id(free_ent_id); - auto ent = entity(*this, new_ent_id); entity_ids_.insert(new_ent_id); free_entity_ids_.pop_back(); - return ent; + return {*this, new_ent_id}; } if ( last_entity_id_ < detail::entity_id_index_mask ) { - auto ent = entity(*this, ++last_entity_id_); - entity_ids_.insert(ent.id()); - return ent; + entity_ids_.insert(last_entity_id_ + 1); + return {*this, ++last_entity_id_}; } throw std::logic_error("ecs_hpp::registry (entity index overlow)"); } - inline bool registry::destroy_entity(const entity& ent) { - remove_all_components_impl_(ent); - if ( entity_ids_.unordered_erase(ent.id()) ) { - free_entity_ids_.push_back(ent.id()); + inline bool registry::destroy_entity(const uentity& ent) { + assert(ent.check_owner(this)); + remove_all_components(ent); + if ( entity_ids_.unordered_erase(ent) ) { + free_entity_ids_.push_back(ent); return true; } return false; } - inline bool registry::is_entity_alive(const const_entity& ent) const noexcept { - return is_entity_alive_impl_(ent); + inline bool registry::alive_entity(const const_uentity& ent) const noexcept { + assert(ent.check_owner(this)); + return entity_ids_.has(ent); } template < typename T, typename... Args > - bool registry::assign_component(const entity& ent, Args&&... args) { - if ( !is_entity_alive_impl_(ent) ) { + bool registry::assign_component(const uentity& ent, Args&&... args) { + assert(ent.check_owner(this)); + if ( !alive_entity(ent) ) { return false; } get_or_create_storage_().assign( - ent.id(), + ent, std::forward(args)...); return true; } template < typename T > - bool registry::remove_component(const entity& ent) { - if ( !is_entity_alive_impl_(ent) ) { + bool registry::remove_component(const uentity& ent) { + assert(ent.check_owner(this)); + if ( !alive_entity(ent) ) { return false; } - const detail::component_storage* storage = find_storage_(); + detail::component_storage* storage = find_storage_(); return storage - ? storage->remove(ent.id()) + ? storage->remove(ent) : false; } template < typename T > - bool registry::exists_component(const const_entity& ent) const noexcept { - if ( !is_entity_alive_impl_(ent) ) { + bool registry::exists_component(const const_uentity& ent) const noexcept { + assert(ent.check_owner(this)); + if ( !alive_entity(ent) ) { return false; } const detail::component_storage* storage = find_storage_(); return storage - ? storage->exists(ent.id()) + ? storage->exists(ent) : false; } - inline std::size_t registry::remove_all_components(const entity& ent) noexcept { - return remove_all_components_impl_(ent); + inline std::size_t registry::remove_all_components(const uentity& ent) noexcept { + assert(ent.check_owner(this)); + if ( !alive_entity(ent) ) { + return 0u; + } + std::size_t removed_count = 0u; + for ( const auto family_id : storages_ ) { + if ( storages_.get(family_id)->remove(ent) ) { + ++removed_count; + } + } + return removed_count; } template < typename T > - T& registry::get_component(const entity& ent) { - T* component = find_component_impl_(ent); + T& registry::get_component(const uentity& ent) { + assert(ent.check_owner(this)); + T* component = find_component(ent); if ( component ) { return *component; } @@ -1161,8 +1355,9 @@ namespace ecs_hpp } template < typename T > - const T& registry::get_component(const const_entity& ent) const { - const T* component = find_component_impl_(ent); + const T& registry::get_component(const const_uentity& ent) const { + assert(ent.check_owner(this)); + const T* component = find_component(ent); if ( component ) { return *component; } @@ -1170,46 +1365,81 @@ namespace ecs_hpp } template < typename T > - T* registry::find_component(const entity& ent) noexcept { - return find_component_impl_(ent); + T* registry::find_component(const uentity& ent) noexcept { + assert(ent.check_owner(this)); + detail::component_storage* storage = find_storage_(); + return storage + ? storage->find(ent) + : nullptr; } template < typename T > - const T* registry::find_component(const const_entity& ent) const noexcept { - return find_component_impl_(ent); + const T* registry::find_component(const const_uentity& ent) const noexcept { + assert(ent.check_owner(this)); + const detail::component_storage* storage = find_storage_(); + return storage + ? storage->find(ent) + : nullptr; } template < typename... Ts > - std::tuple registry::get_components(const entity& ent) { + std::tuple registry::get_components(const uentity& ent) { + assert(ent.check_owner(this)); return std::make_tuple(std::ref(get_component(ent))...); } template < typename... Ts > - std::tuple registry::get_components(const const_entity& ent) const { + std::tuple registry::get_components(const const_uentity& ent) const { + assert(ent.check_owner(this)); return std::make_tuple(std::cref(get_component(ent))...); } template < typename... Ts > - std::tuple registry::find_components(const entity& ent) noexcept { + std::tuple registry::find_components(const uentity& ent) noexcept { + assert(ent.check_owner(this)); return std::make_tuple(find_component(ent)...); } template < typename... Ts > - std::tuple registry::find_components(const const_entity& ent) const noexcept { + std::tuple registry::find_components(const const_uentity& ent) const noexcept { + assert(ent.check_owner(this)); return std::make_tuple(find_component(ent)...); } + template < typename T > + std::size_t registry::component_count() const noexcept { + const detail::component_storage* storage = find_storage_(); + return storage + ? storage->count() + : 0u; + } + + template < typename T > + std::size_t registry::entity_component_count(const const_uentity& ent) const noexcept { + assert(ent.check_owner(this)); + if ( !alive_entity(ent) ) { + return 0u; + } + std::size_t component_count = 0u; + for ( const auto family_id : storages_ ) { + if ( storages_.get(family_id)->has(ent) ) { + ++component_count; + } + } + return component_count; + } + template < typename F > void registry::for_each_entity(F&& f) { for ( const auto id : entity_ids_ ) { - f(entity(*this, id)); + f({*this, id}); } } template < typename F > void registry::for_each_entity(F&& f) const { for ( const auto id : entity_ids_ ) { - f(const_entity(*this, id)); + f({*this, id}); } } @@ -1217,7 +1447,9 @@ namespace ecs_hpp void registry::for_each_component(F&& f) { detail::component_storage* storage = find_storage_(); if ( storage ) { - storage->for_each_component(std::forward(f)); + storage->for_each_component([this, &f](const entity_id e, T& t){ + f(uentity{*this, e}, t); + }); } } @@ -1225,7 +1457,9 @@ namespace ecs_hpp void registry::for_each_component(F&& f) const { const detail::component_storage* storage = find_storage_(); if ( storage ) { - storage->for_each_component(std::forward(f)); + storage->for_each_component([this, &f](const entity_id e, const T& t){ + f(const_uentity{*this, e}, t); + }); } } @@ -1289,39 +1523,6 @@ namespace ecs_hpp storages_.get(family).get()); } - inline bool registry::is_entity_alive_impl_(const const_entity& ent) const noexcept { - return entity_ids_.has(ent.id()); - } - - inline std::size_t registry::remove_all_components_impl_(const entity& ent) noexcept { - if ( !is_entity_alive_impl_(ent) ) { - return 0u; - } - std::size_t removed_components = 0u; - for ( const auto id : storages_ ) { - if ( storages_.get(id)->remove(ent.id()) ) { - ++removed_components; - } - } - return removed_components; - } - - template < typename T > - T* registry::find_component_impl_(const entity& ent) noexcept { - detail::component_storage* storage = find_storage_(); - return storage - ? storage->find(ent.id()) - : nullptr; - } - - template < typename T > - const T* registry::find_component_impl_(const const_entity& ent) const noexcept { - const detail::component_storage* storage = find_storage_(); - return storage - ? storage->find(ent.id()) - : nullptr; - } - template < typename T , typename... Ts , typename F @@ -1334,7 +1535,7 @@ namespace ecs_hpp (void)iseq; const auto ss = std::make_tuple(find_storage_()...); if ( !detail::tuple_contains(ss, nullptr) ) { - for_each_component([this, &f, &ss](const entity& e, T& t) { + for_each_component([this, &f, &ss](const uentity& e, T& t) { for_joined_components_impl_(e, f, ss, t); }); } @@ -1352,7 +1553,7 @@ namespace ecs_hpp (void)iseq; const auto ss = std::make_tuple(find_storage_()...); if ( !detail::tuple_contains(ss, nullptr) ) { - for_each_component([this, &f, &ss](const const_entity& e, const T& t) { + for_each_component([this, &f, &ss](const const_uentity& e, const T& t) { detail::as_const(*this).for_joined_components_impl_(e, f, ss, t); }); } @@ -1364,12 +1565,12 @@ namespace ecs_hpp , typename Ss , typename... Cs > void registry::for_joined_components_impl_( - const entity& e, + const uentity& e, const F& f, const Ss& ss, Cs&... cs) { - T* c = std::get<0>(ss)->find(e.id()); + T* c = std::get<0>(ss)->find(e); if ( c ) { for_joined_components_impl_( e, @@ -1386,12 +1587,12 @@ namespace ecs_hpp , typename Ss , typename... Cs > void registry::for_joined_components_impl_( - const const_entity& e, + const const_uentity& e, const F& f, const Ss& ss, const Cs&... cs) const { - const T* c = std::get<0>(ss)->find(e.id()); + const T* c = std::get<0>(ss)->find(e); if ( c ) { for_joined_components_impl_( e, @@ -1404,7 +1605,7 @@ namespace ecs_hpp template < typename F, typename... Cs > void registry::for_joined_components_impl_( - const entity& e, + const uentity& e, const F& f, const std::tuple<>& ss, Cs&... cs) @@ -1415,7 +1616,7 @@ namespace ecs_hpp template < typename F, typename... Cs > void registry::for_joined_components_impl_( - const const_entity& e, + const const_uentity& e, const F& f, const std::tuple<>& ss, const Cs&... cs) const diff --git a/ecs_tests.cpp b/ecs_tests.cpp index 2a3e690..14ef415 100644 --- a/ecs_tests.cpp +++ b/ecs_tests.cpp @@ -292,8 +292,8 @@ TEST_CASE("registry") { ecs::entity e2{w}; REQUIRE(e1 == e2); - REQUIRE_FALSE(w.is_entity_alive(e1)); - REQUIRE_FALSE(w.is_entity_alive(e2)); + REQUIRE_FALSE(w.alive_entity(e1)); + REQUIRE_FALSE(w.alive_entity(e2)); REQUIRE_FALSE(w.destroy_entity(e1)); REQUIRE_FALSE(w.destroy_entity(e2)); @@ -305,16 +305,16 @@ TEST_CASE("registry") { auto e2 = w.create_entity(); REQUIRE(e1 != e2); - REQUIRE(w.is_entity_alive(e1)); - REQUIRE(w.is_entity_alive(e2)); + REQUIRE(w.alive_entity(e1)); + REQUIRE(w.alive_entity(e2)); REQUIRE(w.destroy_entity(e1)); - REQUIRE_FALSE(w.is_entity_alive(e1)); - REQUIRE(w.is_entity_alive(e2)); + REQUIRE_FALSE(w.alive_entity(e1)); + REQUIRE(w.alive_entity(e2)); REQUIRE(w.destroy_entity(e2)); - REQUIRE_FALSE(w.is_entity_alive(e1)); - REQUIRE_FALSE(w.is_entity_alive(e2)); + REQUIRE_FALSE(w.alive_entity(e1)); + REQUIRE_FALSE(w.alive_entity(e2)); REQUIRE_FALSE(w.destroy_entity(e1)); REQUIRE_FALSE(w.destroy_entity(e2)); @@ -372,13 +372,21 @@ TEST_CASE("registry") { { REQUIRE_FALSE(w.exists_component(e1)); REQUIRE_FALSE(w.exists_component(e1)); + REQUIRE_FALSE(w.component_count()); + REQUIRE_FALSE(w.entity_component_count(e1)); REQUIRE(w.assign_component(e1)); REQUIRE(w.exists_component(e1)); REQUIRE_FALSE(w.exists_component(e1)); + REQUIRE(w.component_count() == 1u); + REQUIRE(w.component_count() == 0u); + REQUIRE(w.entity_component_count(e1) == 1u); REQUIRE(w.assign_component(e1)); + REQUIRE(w.component_count() == 1u); + REQUIRE(w.component_count() == 1u); + REQUIRE(w.entity_component_count(e1) == 2u); REQUIRE(w.exists_component(e1)); REQUIRE(w.exists_component(e1)); @@ -387,6 +395,9 @@ TEST_CASE("registry") { REQUIRE_FALSE(w.exists_component(e1)); REQUIRE_FALSE(w.exists_component(e1)); + REQUIRE_FALSE(w.component_count()); + REQUIRE_FALSE(w.component_count()); + REQUIRE_FALSE(w.entity_component_count(e1)); } { @@ -402,6 +413,11 @@ TEST_CASE("registry") { REQUIRE(e1.exists_component()); REQUIRE(e1.exists_component()); + + REQUIRE(e1.destroy()); + + REQUIRE_FALSE(e1.exists_component()); + REQUIRE_FALSE(e1.exists_component()); } } { @@ -431,6 +447,19 @@ TEST_CASE("registry") { REQUIRE_FALSE(e1.assign_component()); REQUIRE_FALSE(w.exists_component(e1)); } + { + ecs::registry w; + + auto e1 = w.create_entity(); + auto e2 = w.create_entity(); + + REQUIRE(w.assign_component(e1)); + + REQUIRE(w.assign_component(e2)); + REQUIRE(w.assign_component(e2)); + + REQUIRE(e1.destroy()); + } } SECTION("component_accessing") { { @@ -595,6 +624,17 @@ TEST_CASE("registry") { e2.assign_component(5, 6); e2.assign_component(7, 8); + { + ecs::entity_id acc1 = 0; + int acc2 = 0; + w.for_each_component([&acc1, &acc2](ecs::entity_id id, position_c& p){ + acc1 += id; + acc2 += p.x; + }); + REQUIRE(acc1 == e1.id() + e2.id()); + REQUIRE(acc2 == 6); + } + { ecs::entity_id acc1 = 0; int acc2 = 0; @@ -665,6 +705,19 @@ TEST_CASE("registry") { e3.assign_component(100, 500); e4.assign_component(500, 100); + { + ecs::entity_id acc1 = 0; + int acc2 = 0; + w.for_joined_components([&acc1, &acc2]( + ecs::entity_id id, const position_c& p, const velocity_c& v) + { + acc1 += id; + acc2 += p.x + v.x; + }); + REQUIRE(acc1 == e1.id() + e2.id()); + REQUIRE(acc2 == 16); + } + { ecs::entity_id acc1 = 0; int acc2 = 0; @@ -680,16 +733,30 @@ TEST_CASE("registry") { { const ecs::registry& ww = w; - ecs::entity_id acc1 = 0; - int acc2 = 0; - ww.for_joined_components([&acc1, &acc2]( - ecs::const_entity e, const position_c& p, const velocity_c& v) { - acc1 += e.id(); - acc2 += p.x + v.x; - }); - REQUIRE(acc1 == e1.id() + e2.id()); - REQUIRE(acc2 == 16); + ecs::entity_id acc1 = 0; + int acc2 = 0; + ww.for_joined_components([&acc1, &acc2]( + ecs::entity_id id, const position_c& p, const velocity_c& v) + { + acc1 += id; + acc2 += p.x + v.x; + }); + REQUIRE(acc1 == e1.id() + e2.id()); + REQUIRE(acc2 == 16); + } + { + ecs::entity_id acc1 = 0; + int acc2 = 0; + ww.for_joined_components([&acc1, &acc2]( + ecs::const_entity e, const position_c& p, const velocity_c& v) + { + acc1 += e.id(); + acc2 += p.x + v.x; + }); + REQUIRE(acc1 == e1.id() + e2.id()); + REQUIRE(acc2 == 16); + } } } { @@ -740,15 +807,15 @@ TEST_CASE("registry") { TEST_CASE("example") { struct position_component { - float x{0}; - float y{0}; + float x; + float y; position_component(float nx, float ny) : x(nx), y(ny) {} }; struct velocity_component { - float dx{0}; - float dy{0}; + float dx; + float dy; velocity_component(float ndx, float ndy) : dx(ndx), dy(ndy) {} }; @@ -759,7 +826,7 @@ TEST_CASE("example") { owner.for_joined_components< position_component, velocity_component - >([](const ecs_hpp::entity& e, position_component& p, const velocity_component& v) { + >([](const ecs_hpp::entity&, position_component& p, const velocity_component& v) { p.x += v.dx; p.y += v.dy; }); @@ -774,7 +841,7 @@ TEST_CASE("example") { void process(ecs_hpp::registry& owner) override { owner.for_each_component< velocity_component - >([this](const ecs_hpp::entity& e, velocity_component& v) { + >([this](const ecs_hpp::entity&, velocity_component& v) { v.dx += gravity_; v.dy += gravity_; });