added filtered views
This commit is contained in:
24
README.md
24
README.md
@@ -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.
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user