diff --git a/libs/util/include/psemek/util/ecs.hpp b/libs/util/include/psemek/util/ecs.hpp index 63ff8949..de3d0b9d 100644 --- a/libs/util/include/psemek/util/ecs.hpp +++ b/libs/util/include/psemek/util/ecs.hpp @@ -43,6 +43,12 @@ namespace psemek::util virtual handle entity_count() const = 0; virtual handle add_entity() = 0; + virtual void remove_entity(handle h) = 0; + + bool entity_active(handle h) + { + return get_free_list()[h] == h; + } template void apply(Behavior & behavior) @@ -52,6 +58,11 @@ namespace psemek::util virtual ~species_base() {} + static constexpr handle null = static_cast(-1); + + virtual handle const * get_free_list() = 0; + virtual std::size_t list_size() const = 0; + private: template @@ -90,12 +101,16 @@ namespace psemek::util ((++ptrs), ...); }; - std::size_t const count = entity_count(); + auto list = get_free_list(); + + std::size_t const count = list_size(); for (std::size_t i = 0; i < count; ++i) { - std::apply(visit, cptrs); + if (*list == i) + std::apply(visit, cptrs); std::apply(increment, cptrs); + ++list; } } }; @@ -129,20 +144,38 @@ namespace psemek::util handle entity_count() const override { - return std::get<0>(entity_components_).size(); + return entity_count_; } handle add_entity() override { - handle result = entity_count(); - add_entity_impl(std::make_index_sequence{}); - return result; + return add_entity_impl(std::make_index_sequence{}); + } + + void remove_entity(handle h) override + { + list_[h] = list_head_; + list_head_ = h; + --entity_count_; + } + + handle const * get_free_list() override + { + return list_.data(); + } + + std::size_t list_size() const override + { + return list_.size(); } private: std::string name_; std::tuple species_components_; std::tuple...> entity_components_; + std::vector list_; + handle list_head_ = null; + std::size_t entity_count_ = 0; template void * get_species_component_impl(std::type_index component_type, std::index_sequence) @@ -163,46 +196,30 @@ namespace psemek::util } template - void add_entity_impl(std::index_sequence) + handle add_entity_impl(std::index_sequence) { - ((std::get(entity_components_).emplace_back()), ...); + if (list_head_ == null) + { + std::size_t const old_size = list_.size(); + std::size_t const new_size = std::max(16, old_size * 2); + + list_.resize(new_size); + for (std::size_t i = old_size; i + 1 < new_size; ++i) + list_[i] = i + 1; + list_[new_size - 1] = null; + list_head_ = old_size; + + ((std::get(entity_components_).resize(new_size)), ...); + } + + auto result = list_head_; + list_head_ = list_[list_head_]; + list_[result] = result; + entity_count_++; + return result; } }; - template <> - struct species_impl<> - : species_base - { - species_impl(std::string name) - : name_(std::move(name)) - {} - - std::string_view name() const override - { - return name_; - } - - using species_base::get_species_component; - using species_base::get_entity_component; - - void * get_species_component(std::type_index) override { return nullptr; } - void * get_entity_component(std::type_index) override { return nullptr; } - - virtual handle entity_count() const - { - return entity_count_; - } - - virtual handle add_entity() - { - return entity_count_++; - } - - private: - std::string name_; - std::size_t entity_count_ = 0; - }; - template using prepare_helper = decltype(std::declval().prepare()); @@ -227,6 +244,10 @@ namespace psemek::util handle add_entity(handle species); handle entity_count(handle species) const; + void remove_entity(handle species, handle entity); + bool entity_active(handle species, handle entity); + + handle capacity(handle species) const { return species_[species]->list_size(); } template Component & get(handle species); @@ -265,6 +286,16 @@ namespace psemek::util return species_[species]->entity_count(); } + inline void ecs::remove_entity(handle species, handle entity) + { + species_[species]->remove_entity(entity); + } + + inline bool ecs::entity_active(handle species, handle entity) + { + return species_[species]->entity_active(entity); + } + template Component & ecs::get(handle species) {