added filtered views

This commit is contained in:
Michele Caini
2017-05-29 13:51:49 +02:00
parent 91936d1bcc
commit 388175968d
3 changed files with 88 additions and 11 deletions

View File

@@ -73,6 +73,12 @@ int main() {
else { ecs.destroy(entity); }
}
std::cout << "filtered component view" << std::endl;
for(auto entity: ecs.view<Position>().exclude<Velocity>()) {
std::cout << (registry.has<Position>(entity)) << "/" << (registry.has<Velocity>(entity)) << std::endl;
}
ecs.reset();
}
```
@@ -189,12 +195,13 @@ Note that entities are numbers and nothing more. They are not classes and they h
#### The View
There are two different kinds of view, each one with a slighlty different interface:
There are three different kinds of view, each one with a slighlty different interface:
* The _single component view_.
* The _multi component view_.
* The _filtered view_.
Both of them are iterable, that is both of them have `begin` and `end` member functions that are suitable for a range-based for loop:
All of them are iterable. In other terms they have `begin` and `end` member functions that are suitable for a range-based for loop:
```
auto view = registry.view<Position, Velocity>();
@@ -221,7 +228,18 @@ The multi component view has an additional member function:
* `reset()`: reorganizes internal data so as to further create optimized iterators (use it whenever the data within the registry are known to be changed).
Both the views can be used more than once. They return newly created and correctly initialized iterators whenever
The filtered view is nothing more than a multi component view with an additional set of components that act as filters.<br/>
Users can create filtered view either from a single component view or from a multi component view by means of the `exclude` member function:
```
auto view = registry.view<Position>().exclude<Velocity>();
for(auto entity: view) {
// do whatever you want with your entities
}
```
All the views can be used more than once. They return newly created and correctly initialized iterators whenever
`begin` or `end` is invoked. Anyway views and iterators are tiny objects and the time to construct them can be safely ignored.
I'd suggest not to store them anywhere and to invoke the `Registry::view` member function at each iteration to get a properly
initialized view over which to iterate.

View File

@@ -2,6 +2,7 @@
#define ENTT_REGISTRY_HPP
#include <tuple>
#include <vector>
#include <utility>
#include <cstddef>
@@ -16,8 +17,8 @@ template<typename...>
class View;
template<template<typename...> class Pool, typename Entity, typename... Components, typename Type, typename... Types>
class View<Pool<Entity, Components...>, Type, Types...> final {
template<template<typename...> class Pool, typename Entity, typename... Components, typename Type, typename... Types, typename... Filters>
class View<Pool<Entity, Components...>, std::tuple<Type, Types...>, std::tuple<Filters...>> final {
using pool_type = Pool<Entity, Components...>;
using entity_type = typename pool_type::entity_type;
@@ -25,9 +26,9 @@ class View<Pool<Entity, Components...>, Type, Types...> final {
bool valid() const noexcept {
using accumulator_type = bool[];
bool check = pool.template has<Type>(entities[pos-1]);
accumulator_type accumulator = { true, (check = check && pool.template has<Types>(entities[pos-1]))... };
(void)accumulator;
return check;
accumulator_type types = { true, (check = check && pool.template has<Types>(entities[pos-1]))... };
accumulator_type filters = { true, (check = check && not pool.template has<Filters>(entities[pos-1]))... };
return void(types), void(filters), check;
}
public:
@@ -85,6 +86,9 @@ public:
using iterator_type = ViewIterator;
using size_type = typename pool_type::size_type;
template<typename... Comp>
using view_type = View<pool_type, std::tuple<Type, Types...>, std::tuple<Comp...>>;
explicit View(pool_type &pool) noexcept
: entities{pool.template entities<Type>()},
size{pool.template size<Type>()},
@@ -95,6 +99,11 @@ public:
(void)accumulator;
}
template<typename... Comp>
view_type<Comp...> exclude() noexcept {
return view_type<Comp...>{pool};
}
iterator_type begin() const noexcept {
return ViewIterator{pool, entities, size};
}
@@ -119,7 +128,7 @@ private:
template<template<typename...> class Pool, typename Entity, typename... Components, typename Type>
class View<Pool<Entity, Components...>, Type> final {
class View<Pool<Entity, Components...>, std::tuple<Type>, std::tuple<>> final {
using pool_type = Pool<Entity, Components...>;
using entity_type = typename pool_type::entity_type;
@@ -165,8 +174,16 @@ public:
using iterator_type = ViewIterator;
using size_type = typename pool_type::size_type;
template<typename... Comp>
using view_type = View<pool_type, std::tuple<Type>, std::tuple<Comp...>>;
explicit View(pool_type &pool) noexcept: pool{pool} {}
template<typename... Comp>
view_type<Comp...> exclude() noexcept {
return view_type<Comp...>{pool};
}
iterator_type begin() const noexcept {
return ViewIterator{pool.template entities<Type>(), pool.template size<Type>()};
}
@@ -229,7 +246,7 @@ private:
public:
template<typename... Comp>
using view_type = View<pool_type, Comp...>;
using view_type = View<pool_type, std::tuple<Comp...>, std::tuple<>>;
template<typename... Args>
Registry(Args&&... args)
@@ -367,7 +384,7 @@ public:
}
template<typename... Comp>
view_type<Comp...> view() {
view_type<Comp...> view() noexcept {
return view_type<Comp...>{pool};
}

View File

@@ -193,3 +193,45 @@ TEST(DefaultRegistry, EmptyViewMultipleComponent) {
registry.reset();
}
TEST(DefaultRegistry, ViewSingleComponentWithExclude) {
using registry_type = entt::DefaultRegistry<int, char>;
registry_type registry;
registry_type::entity_type e1 = registry.create<char>();
registry_type::entity_type e2 = registry.create<int, char>();
auto view = registry.view<char>().exclude<int>();
ASSERT_NE(view.begin(), view.end());
ASSERT_EQ(*view.begin(), e1);
ASSERT_NE(*view.begin(), e2);
ASSERT_EQ(++view.begin(), view.end());
ASSERT_NO_THROW(registry.reset());
ASSERT_NO_THROW((registry.view<char>().exclude<int>().begin()++));
ASSERT_NO_THROW((++registry.view<char>().exclude<int>().begin()));
}
TEST(DefaultRegistry, ViewMultipleComponentWithExclude) {
using registry_type = entt::DefaultRegistry<int, char, double>;
registry_type registry;
registry_type::entity_type e1 = registry.create<int, char, double>();
registry_type::entity_type e2 = registry.create<char, double>();
auto view = registry.view<char, double>().exclude<int>();
ASSERT_NE(view.begin(), view.end());
ASSERT_NE(*view.begin(), e1);
ASSERT_EQ(*view.begin(), e2);
ASSERT_EQ(++view.begin(), view.end());
ASSERT_NO_THROW(registry.reset());
ASSERT_NO_THROW((registry.view<char>().exclude<int>().begin()++));
ASSERT_NO_THROW((++registry.view<char>().exclude<int>().begin()));
}