add minimal aspects

This commit is contained in:
2019-10-17 10:56:07 +07:00
parent 6b34c00b34
commit 346e819529
2 changed files with 199 additions and 0 deletions

View File

@@ -55,6 +55,10 @@ namespace ecs_hpp
class option_conj;
template < typename... Ts >
class option_disj;
class option_bool;
template < typename... Ts >
class aspect;
class entity_filler;
class registry_filler;
@@ -1390,6 +1394,18 @@ namespace ecs_hpp
template < typename T >
detail::component_storage<T>& get_or_create_storage_();
template < typename F, typename... Opts >
void for_joined_components_impl_(
std::index_sequence<>,
F&& f,
Opts&&... opts);
template < typename F, typename... Opts >
void for_joined_components_impl_(
std::index_sequence<>,
F&& f,
Opts&&... opts) const;
template < typename T
, typename... Ts
, typename F
@@ -1508,6 +1524,11 @@ namespace ecs_hpp
static constexpr bool instance = true;
};
template <>
struct option<option_bool> {
static constexpr bool instance = true;
};
//
// options
//
@@ -1583,6 +1604,19 @@ namespace ecs_hpp
std::tuple<Ts...> opts_;
};
class option_bool final {
public:
option_bool(bool b)
: bool_(b) {}
bool operator()(const const_entity& e) const {
(void)e;
return bool_;
}
private:
bool bool_{false};
};
//
// operators
//
@@ -1608,6 +1642,57 @@ namespace ecs_hpp
}
}
// -----------------------------------------------------------------------------
//
// aspect
//
// -----------------------------------------------------------------------------
namespace ecs_hpp
{
template < typename... Ts >
class aspect {
public:
static auto to_option() noexcept {
return (option_bool{true} && ... && exists<Ts>{});
}
static bool match_entity(const const_entity& e) noexcept {
return (... && e.exists_component<Ts>());
}
template < typename F, typename... Opts >
static void for_each_entity(registry& owner, F&& f, Opts&&... opts) {
owner.for_joined_components<Ts...>(
[&f](const auto& e, const auto&...){
f(e);
}, std::forward<Opts>(opts)...);
}
template < typename F, typename... Opts >
static void for_each_entity(const registry& owner, F&& f, Opts&&... opts) {
owner.for_joined_components<Ts...>(
[&f](const auto& e, const auto&...){
f(e);
}, std::forward<Opts>(opts)...);
}
template < typename F, typename... Opts >
static void for_joined_components(registry& owner, F&& f, Opts&&... opts) {
owner.for_joined_components<Ts...>(
std::forward<F>(f),
std::forward<Opts>(opts)...);
}
template < typename F, typename... Opts >
static void for_joined_components(const registry& owner, F&& f, Opts&&... opts) {
owner.for_joined_components<Ts...>(
std::forward<F>(f),
std::forward<Opts>(opts)...);
}
};
}
// -----------------------------------------------------------------------------
//
// fillers
@@ -2683,6 +2768,24 @@ namespace ecs_hpp
storages_.get(family).get());
}
template < typename F, typename... Opts >
void registry::for_joined_components_impl_(
std::index_sequence<>,
F&& f,
Opts&&... opts)
{
for_each_entity(std::forward<F>(f), std::forward<Opts>(opts)...);
}
template < typename F, typename... Opts >
void registry::for_joined_components_impl_(
std::index_sequence<>,
F&& f,
Opts&&... opts) const
{
for_each_entity(std::forward<F>(f), std::forward<Opts>(opts)...);
}
template < typename T
, typename... Ts
, typename F

View File

@@ -1185,6 +1185,102 @@ TEST_CASE("registry") {
});
}
}
SECTION("aspects") {
{
using empty_aspect = ecs::aspect<>;
ecs::registry w;
ecs::entity e1 = w.create_entity();
REQUIRE(empty_aspect::match_entity(e1));
ecs::entity e2 = w.create_entity();
e2.assign_component<movable_c>();
e2.assign_component<position_c>(1,2);
REQUIRE(empty_aspect::match_entity(e2));
ecs::entity e3 = w.create_entity();
e3.assign_component<movable_c>();
e3.assign_component<position_c>(1,2);
e3.assign_component<velocity_c>(3,4);
REQUIRE(empty_aspect::match_entity(e3));
{
ecs::entity_id acc{};
empty_aspect::for_each_entity(w, [&acc](ecs::entity e){
acc += e.id();
}, ecs::exists<movable_c>{});
REQUIRE(acc == e2.id() + e3.id());
}
{
ecs::entity_id acc{};
empty_aspect::for_joined_components(w, [&acc](ecs::entity e){
acc += e.id();
}, ecs::exists<movable_c>{});
REQUIRE(acc == e2.id() + e3.id());
}
{
ecs::entity_id acc{};
w.for_each_entity([&acc](ecs::entity e){
acc += e.id();
}, empty_aspect::to_option());
REQUIRE(acc == e1.id() + e2.id() + e3.id());
}
}
{
using movable = ecs::aspect<
position_c,
velocity_c>;
ecs::registry w;
ecs::entity e = w.create_entity();
REQUIRE_FALSE(movable::match_entity(e));
e.assign_component<position_c>(1,2);
REQUIRE_FALSE(movable::match_entity(e));
e.assign_component<velocity_c>(3,4);
REQUIRE(movable::match_entity(e));
ecs::entity e2 = w.create_entity();
e2.assign_component<position_c>(1,2);
movable::for_joined_components(w,
[](ecs::entity_id, position_c& p, const velocity_c& v){
p.x += v.x;
p.y += v.y;
});
movable::for_joined_components(std::as_const(w),
[](ecs::entity_id, const position_c& p, const velocity_c& v){
const_cast<position_c&>(p).x += v.x;
const_cast<position_c&>(p).y += v.y;
});
w.for_each_entity([](ecs::entity e){
auto& p = e.get_component<position_c>();
const auto& v = e.get_component<velocity_c>();
p.x += v.x;
p.y += v.y;
}, movable::to_option());
std::as_const(w).for_each_entity([](const ecs::const_entity& e){
const auto& p = e.get_component<position_c>();
const auto& v = e.get_component<velocity_c>();
const_cast<position_c&>(p).x += v.x;
const_cast<position_c&>(p).y += v.y;
}, movable::to_option());
REQUIRE(e.get_component<position_c>().x == 1 + 3*4);
REQUIRE(e.get_component<position_c>().y == 2 + 4*4);
REQUIRE(e2.get_component<position_c>().x == 1);
REQUIRE(e2.get_component<position_c>().y == 2);
}
}
SECTION("options") {
{
ecs::registry w;