Introduce util::ecs::behavior::context

This commit is contained in:
Nikita Lisitsa 2021-07-24 11:14:39 +03:00
parent bc7378456b
commit 02b29af95a

View file

@ -23,7 +23,12 @@ namespace psemek::util
struct species_base
{
virtual std::string_view name() const = 0;
species_base(std::string name, handle id)
: name_(std::move(name))
, id_(id)
{}
std::string_view name() const { return name_; }
virtual void * get_species_component(std::type_index component_type) = 0;
virtual void * get_entity_component(std::type_index component_type) = 0;
@ -65,6 +70,9 @@ namespace psemek::util
private:
std::string name_;
handle id_;
template <typename Behavior, typename ... Components, std::size_t ... Is>
void apply_impl(Behavior & behavior, std::tuple<Components...> *, std::index_sequence<Is...>)
{
@ -80,15 +88,16 @@ namespace psemek::util
if (!std::apply(all_nonzero, cptrs))
return;
std::tuple<Components *...> cs;
typename Behavior::context ctx;
ctx.species = id_;
((std::get<Components *>(cs) = get_species_component<Components>()), ...);
((std::get<Components *>(ctx.components) = get_species_component<Components>()), ...);
auto visit = [&](auto * ... ptrs)
{
if constexpr (std::is_invocable_v<Behavior, typename Components::data & ..., std::tuple<Components *...> const &>)
if constexpr (std::is_invocable_v<Behavior, typename Components::data & ..., typename Behavior::context &>)
{
behavior(*ptrs..., cs);
behavior(*ptrs..., ctx);
}
else
{
@ -108,7 +117,10 @@ namespace psemek::util
for (std::size_t i = 0; i < count; ++i)
{
if (*list == i)
{
ctx.entity = i;
std::apply(visit, cptrs);
}
std::apply(increment, cptrs);
++list;
}
@ -119,16 +131,11 @@ namespace psemek::util
struct species_impl
: species_base
{
species_impl(std::string name, Components && ... components)
: name_(std::move(name))
species_impl(std::string name, handle id, Components && ... components)
: species_base(std::move(name), id)
, species_components_{std::move(components)...}
{}
std::string_view name() const override
{
return name_;
}
using species_base::get_species_component;
using species_base::get_entity_component;
@ -170,7 +177,6 @@ namespace psemek::util
}
private:
std::string name_;
std::tuple<Components...> species_components_;
std::tuple<std::vector<typename Components::data>...> entity_components_;
std::vector<handle> list_;
@ -220,12 +226,6 @@ namespace psemek::util
}
};
template <typename Behavior>
using prepare_helper = decltype(std::declval<Behavior>().prepare());
template <typename Behavior>
using has_prepare = std::experimental::is_detected<prepare_helper, Behavior>;
}
struct ecs
@ -235,6 +235,20 @@ namespace psemek::util
{
using component_types = std::tuple<Components...>;
using component_ptrs = std::tuple<Components *...>;
struct context
{
ecs_detail::handle species;
ecs_detail::handle entity;
component_ptrs components;
template <typename Component>
Component & get() const
{
return *std::get<Component *>(components);
}
};
};
using handle = ecs_detail::handle;
@ -280,6 +294,9 @@ namespace psemek::util
template <typename Behavior>
void apply(Behavior && behavior) const;
template <typename Behavior>
void apply(Behavior && behavior, handle species) const;
private:
std::vector<std::unique_ptr<ecs_detail::species_base>> species_;
};
@ -288,7 +305,7 @@ namespace psemek::util
ecs::handle ecs::register_species(std::string name, Components && ... components)
{
handle result = species_.size();
species_.push_back(std::make_unique<ecs_detail::species_impl<Components...>>(std::move(name), std::move(components)...));
species_.push_back(std::make_unique<ecs_detail::species_impl<Components...>>(std::move(name), result, std::move(components)...));
return result;
}
@ -372,13 +389,14 @@ namespace psemek::util
template <typename Behavior>
void ecs::apply(Behavior && behavior) const
{
if constexpr (ecs_detail::has_prepare<Behavior>::value)
{
behavior.prepare();
}
for (auto & s : species_)
s->apply(behavior);
}
template <typename Behavior>
void ecs::apply(Behavior && behavior, handle species) const
{
species_[species]->apply(behavior);
}
}