Merge pull request #36 from BlackMATov/dev

Dev
This commit is contained in:
2019-10-15 11:13:30 +07:00
committed by GitHub
6 changed files with 477 additions and 302 deletions

View File

@@ -1,9 +1,8 @@
version: "{build}" version: "{build}"
shallow_clone: true shallow_clone: true
image: image:
- Visual Studio 2015
- Visual Studio 2017 - Visual Studio 2017
- Visual Studio 2019 Preview - Visual Studio 2019
platform: platform:
- Win32 - Win32
- x64 - x64

View File

@@ -1,18 +1,6 @@
language: cpp language: cpp
matrix: matrix:
include: include:
- os: linux
dist: trusty
addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-4.9"] } }
env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9"
- os: linux
dist: trusty
addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-5"] } }
env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
- os: linux
dist: trusty
addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-6"] } }
env: MATRIX_EVAL="CC=gcc-6 && CXX=g++-6"
- os: linux - os: linux
dist: trusty dist: trusty
addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-7"] } } addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-7"] } }
@@ -23,42 +11,12 @@ matrix:
env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
- os: linux - os: linux
dist: trusty dist: trusty
addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-precise-3.8"], packages: ["xorg-dev", "clang-3.8", "g++-5"] } } addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-7"], packages: ["xorg-dev", "clang-7", "g++-7"] } }
env: MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" env: MATRIX_EVAL="CC=clang-7 && CXX=clang++-7"
- os: linux - os: linux
dist: trusty dist: trusty
addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-precise-3.9"], packages: ["xorg-dev", "clang-3.9", "g++-5"] } } addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-8"], packages: ["xorg-dev", "clang-8", "g++-7"] } }
env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" env: MATRIX_EVAL="CC=clang-8 && CXX=clang++-8"
- os: linux
dist: trusty
addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-4.0"], packages: ["xorg-dev", "clang-4.0", "g++-5"] } }
env: MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0"
- os: linux
dist: trusty
addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-5.0"], packages: ["xorg-dev", "clang-5.0", "g++-7"] } }
env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0"
- os: linux
dist: trusty
addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-6.0"], packages: ["xorg-dev", "clang-6.0", "g++-7"] } }
env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0"
- os: osx
osx_image: xcode8.3
compiler: clang
- os: osx
osx_image: xcode9
compiler: clang
- os: osx
osx_image: xcode9.1
compiler: clang
- os: osx
osx_image: xcode9.2
compiler: clang
- os: osx
osx_image: xcode9.3
compiler: clang
- os: osx
osx_image: xcode9.4
compiler: clang
- os: osx - os: osx
osx_image: xcode10 osx_image: xcode10
compiler: clang compiler: clang
@@ -69,7 +27,6 @@ before_install:
- if [ "$TRAVIS_OS_NAME" == 'osx' ]; then - if [ "$TRAVIS_OS_NAME" == 'osx' ]; then
brew update; brew update;
brew upgrade cmake; brew upgrade cmake;
brew install git-lfs;
fi fi
- if [ "$TRAVIS_OS_NAME" == 'linux' ]; then - if [ "$TRAVIS_OS_NAME" == 'linux' ]; then
mkdir $HOME/cmake; mkdir $HOME/cmake;

View File

@@ -1,4 +1,4 @@
# 3.8 version is required for `cxx_std_14` # 3.8 version is required for `cxx_std_17`
cmake_minimum_required(VERSION 3.8 FATAL_ERROR) cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
if(NOT DEFINED PROJECT_NAME) if(NOT DEFINED PROJECT_NAME)
@@ -9,7 +9,7 @@ project(ecs.hpp)
add_library(${PROJECT_NAME} INTERFACE) add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(${PROJECT_NAME} INTERFACE headers) target_include_directories(${PROJECT_NAME} INTERFACE headers)
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_14) target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17)
if(BUILD_AS_STANDALONE) if(BUILD_AS_STANDALONE)
option(BUILD_WITH_UNBENCH "Build with benchmarks" OFF) option(BUILD_WITH_UNBENCH "Build with benchmarks" OFF)

View File

@@ -10,14 +10,14 @@
[badge.travis]: https://img.shields.io/travis/BlackMATov/ecs.hpp/master.svg?logo=travis [badge.travis]: https://img.shields.io/travis/BlackMATov/ecs.hpp/master.svg?logo=travis
[badge.appveyor]: https://img.shields.io/appveyor/ci/BlackMATov/ecs-hpp/master.svg?logo=appveyor [badge.appveyor]: https://img.shields.io/appveyor/ci/BlackMATov/ecs-hpp/master.svg?logo=appveyor
[badge.codecov]: https://img.shields.io/codecov/c/github/BlackMATov/ecs.hpp/master.svg?logo=codecov [badge.codecov]: https://img.shields.io/codecov/c/github/BlackMATov/ecs.hpp/master.svg?logo=codecov
[badge.language]: https://img.shields.io/badge/language-C%2B%2B14-red.svg [badge.language]: https://img.shields.io/badge/language-C%2B%2B17-yellow.svg
[badge.license]: https://img.shields.io/badge/license-MIT-blue.svg [badge.license]: https://img.shields.io/badge/license-MIT-blue.svg
[badge.paypal]: https://img.shields.io/badge/donate-PayPal-orange.svg?logo=paypal&colorA=00457C [badge.paypal]: https://img.shields.io/badge/donate-PayPal-orange.svg?logo=paypal&colorA=00457C
[travis]: https://travis-ci.org/BlackMATov/ecs.hpp [travis]: https://travis-ci.org/BlackMATov/ecs.hpp
[appveyor]: https://ci.appveyor.com/project/BlackMATov/ecs-hpp [appveyor]: https://ci.appveyor.com/project/BlackMATov/ecs-hpp
[codecov]: https://codecov.io/gh/BlackMATov/ecs.hpp [codecov]: https://codecov.io/gh/BlackMATov/ecs.hpp
[language]: https://en.wikipedia.org/wiki/C%2B%2B14 [language]: https://en.wikipedia.org/wiki/C%2B%2B17
[license]: https://en.wikipedia.org/wiki/MIT_License [license]: https://en.wikipedia.org/wiki/MIT_License
[paypal]: https://www.paypal.me/matov [paypal]: https://www.paypal.me/matov
@@ -41,61 +41,71 @@ target_link_libraries(your_project_target ecs.hpp)
## Basic usage ## Basic usage
```cpp ```cpp
struct position_component {
float x; #include <ecs.hpp/ecs.hpp>
float y; namespace ecs = ecs_hpp;
position_component(float nx, float ny)
: x(nx), y(ny) {} struct movable {};
struct disabled {};
struct position {
float x{};
float y{};
}; };
struct velocity_component { struct velocity {
float dx; float dx{};
float dy; float dy{};
velocity_component(float ndx, float ndy)
: dx(ndx), dy(ndy) {}
}; };
class movement_system : public ecs_hpp::system { class movement_system : public ecs::system {
public: public:
void process(ecs_hpp::registry& owner) override { void process(ecs::registry& owner) override {
owner.for_joined_components< owner.for_joined_components<
position_component, position,
velocity_component velocity
>([](const ecs_hpp::entity& e, position_component& p, const velocity_component& v) { >([](ecs::entity, position& p, const velocity& v) {
p.x += v.dx; p.x += v.dx;
p.y += v.dy; p.y += v.dy;
}); }, ecs::require<movable>{}, ecs::filter<disabled>{});
} }
}; };
class gravity_system : public ecs_hpp::system { class gravity_system : public ecs::system {
public: public:
gravity_system(float gravity) gravity_system(float gravity)
: gravity_(gravity) {} : gravity_(gravity) {}
void process(ecs_hpp::registry& owner) override { void process(ecs::registry& owner) override {
owner.for_each_component< owner.for_each_component<
velocity_component velocity
>([this](const ecs_hpp::entity& e, velocity_component& v) { >([this](ecs::entity e, velocity& v) {
v.dx += gravity_; v.dx += gravity_;
v.dy += gravity_; v.dy += gravity_;
}); }, ecs::filter<disabled>{});
} }
private: private:
float gravity_; float gravity_{};
}; };
ecs_hpp::registry world; ecs::registry world;
world.add_system<movement_system>(0);
world.add_system<gravity_system>(1, 9.8f); ecs::registry_filler(world)
.system<movement_system>(0)
.system<gravity_system>(1, 9.8f);
auto entity_one = world.create_entity(); auto entity_one = world.create_entity();
world.assign_component<position_component>(entity_one, 4.f, 2.f); ecs::entity_filler(entity_one)
world.assign_component<velocity_component>(entity_one, 10.f, 20.f); .component<movable>()
.component<position>(4.f, 2.f)
.component<velocity>(10.f, 20.f);
auto entity_two = world.create_entity(); auto entity_two = world.create_entity();
entity_two.assign_component<position_component>(4.f, 2.f); ecs::entity_filler(entity_two)
entity_two.assign_component<velocity_component>(10.f, 20.f); .component<movable>()
.component<disabled>()
.component<position>(4.f, 2.f)
.component<velocity>(10.f, 20.f);
world.process_all_systems(); world.process_all_systems();
``` ```

View File

@@ -42,6 +42,21 @@ namespace ecs_hpp
class system; class system;
class registry; class registry;
template < typename... Ts >
class filter_any;
template < typename... Ts >
class filter_all;
template < typename... Ts >
class require_any;
template < typename... Ts >
class require_all;
template < typename... Ts >
using filter = filter_any<Ts...>;
template < typename... Ts >
using require = require_all<Ts...>;
class entity_filler; class entity_filler;
class registry_filler; class registry_filler;
@@ -53,11 +68,11 @@ namespace ecs_hpp
constexpr std::size_t entity_id_version_bits = 10u; constexpr std::size_t entity_id_version_bits = 10u;
static_assert( static_assert(
std::is_unsigned<family_id>::value, std::is_unsigned_v<family_id>,
"ecs_hpp (family_id must be an unsigned integer)"); "ecs_hpp (family_id must be an unsigned integer)");
static_assert( static_assert(
std::is_unsigned<entity_id>::value, std::is_unsigned_v<entity_id>,
"ecs_hpp (entity_id must be an unsigned integer)"); "ecs_hpp (entity_id must be an unsigned integer)");
static_assert( static_assert(
@@ -77,15 +92,6 @@ namespace ecs_hpp
{ {
namespace detail namespace detail
{ {
//
// as_const
//
template < typename T >
constexpr std::add_const_t<T>& as_const(T& t) noexcept {
return t;
}
// //
// hash_combine // hash_combine
// //
@@ -102,21 +108,19 @@ namespace ecs_hpp
{ {
template < typename T, typename... Ts, std::size_t... Is > template < typename T, typename... Ts, std::size_t... Is >
std::tuple<Ts...> tuple_tail_impl( std::tuple<Ts...> tuple_tail_impl(
std::tuple<T, Ts...>&& t, std::index_sequence<Is...>,
std::index_sequence<Is...> iseq) std::tuple<T, Ts...>&& t)
{ {
(void)t; (void)t;
(void)iseq;
return std::make_tuple(std::move(std::get<Is + 1u>(t))...); return std::make_tuple(std::move(std::get<Is + 1u>(t))...);
} }
template < typename T, typename... Ts, std::size_t... Is > template < typename T, typename... Ts, std::size_t... Is >
std::tuple<Ts...> tuple_tail_impl( std::tuple<Ts...> tuple_tail_impl(
const std::tuple<T, Ts...>& t, std::index_sequence<Is...>,
std::index_sequence<Is...> iseq) const std::tuple<T, Ts...>& t)
{ {
(void)t; (void)t;
(void)iseq;
return std::make_tuple(std::get<Is + 1u>(t)...); return std::make_tuple(std::get<Is + 1u>(t)...);
} }
} }
@@ -124,15 +128,15 @@ namespace ecs_hpp
template < typename T, typename... Ts > template < typename T, typename... Ts >
std::tuple<Ts...> tuple_tail(std::tuple<T, Ts...>&& t) { std::tuple<Ts...> tuple_tail(std::tuple<T, Ts...>&& t) {
return impl::tuple_tail_impl( return impl::tuple_tail_impl(
std::move(t), std::make_index_sequence<sizeof...(Ts)>(),
std::make_index_sequence<sizeof...(Ts)>()); std::move(t));
} }
template < typename T, typename... Ts > template < typename T, typename... Ts >
std::tuple<Ts...> tuple_tail(const std::tuple<T, Ts...>& t) { std::tuple<Ts...> tuple_tail(const std::tuple<T, Ts...>& t) {
return impl::tuple_tail_impl( return impl::tuple_tail_impl(
t, std::make_index_sequence<sizeof...(Ts)>(),
std::make_index_sequence<sizeof...(Ts)>()); t);
} }
// //
@@ -141,47 +145,23 @@ namespace ecs_hpp
namespace impl namespace impl
{ {
template < size_t I, typename V, typename... Ts > template < typename V, typename... Ts, std::size_t... Is >
std::enable_if_t<I == sizeof...(Ts), bool> bool tuple_contains_impl(
tuple_contains_impl(const std::tuple<Ts...>& t, const V& v) { std::index_sequence<Is...>,
(void)t; const std::tuple<Ts...>& t,
(void)v; const V& v)
return false; {
} (void)t; (void)v;
return (... || (std::get<Is>(t) == v));
template < size_t I, typename V, typename... Ts >
std::enable_if_t<I != sizeof...(Ts), bool>
tuple_contains_impl(const std::tuple<Ts...>& t, const V& v) {
if ( std::get<I>(t) == v ) {
return true;
}
return tuple_contains_impl<I + 1>(t, v);
} }
} }
template < typename V, typename... Ts > template < typename V, typename... Ts >
bool tuple_contains(const std::tuple<Ts...>& t, const V& v) { bool tuple_contains(const std::tuple<Ts...>& t, const V& v) {
return impl::tuple_contains_impl<0>(t, v); return impl::tuple_contains_impl(
} std::make_index_sequence<sizeof...(Ts)>(),
t,
// v);
// tiny_tuple_apply
//
namespace impl
{
template < typename F, typename Tuple, std::size_t... I >
void tiny_tuple_apply_impl(F&& f, Tuple&& args, std::index_sequence<I...>) {
std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...);
}
}
template < typename F, typename Tuple >
void tiny_tuple_apply(F&& f, Tuple&& args) {
impl::tiny_tuple_apply_impl(
std::forward<F>(f),
std::forward<Tuple>(args),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
} }
// //
@@ -242,7 +222,7 @@ namespace ecs_hpp
template < typename Void = void > template < typename Void = void >
class type_family_base { class type_family_base {
static_assert( static_assert(
std::is_void<Void>::value, std::is_void_v<Void>,
"unexpected internal error"); "unexpected internal error");
protected: protected:
static family_id last_id_; static family_id last_id_;
@@ -273,24 +253,23 @@ namespace ecs_hpp
{ {
namespace detail namespace detail
{ {
template < typename T template < typename T >
, bool = std::is_unsigned<T>::value struct sparse_indexer final {
&& sizeof(T) <= sizeof(std::size_t) > static_assert(std::is_unsigned_v<T>);
struct sparse_unsigned_indexer { static_assert(sizeof(T) <= sizeof(std::size_t));
std::size_t operator()(const T v) const noexcept { std::size_t operator()(const T v) const noexcept {
return static_cast<std::size_t>(v); return static_cast<std::size_t>(v);
} }
}; };
template < typename T >
struct sparse_unsigned_indexer<T, false> {};
template < typename T >
struct sparse_indexer final
: public sparse_unsigned_indexer<T> {};
} }
} }
// -----------------------------------------------------------------------------
//
// detail::incremental_locker
//
// -----------------------------------------------------------------------------
namespace ecs_hpp namespace ecs_hpp
{ {
namespace detail namespace detail
@@ -354,14 +333,6 @@ namespace ecs_hpp
public: public:
using iterator = typename std::vector<T>::iterator; using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator; using const_iterator = typename std::vector<T>::const_iterator;
public:
static_assert(
noexcept(std::declval<Indexer>()(std::declval<T>())),
"unsupported sparse_set indexer");
static_assert(
std::is_nothrow_move_assignable<T>::value &&
noexcept(std::declval<T>() == std::declval<T>()),
"unsupported sparse_set value type");
public: public:
iterator begin() noexcept { iterator begin() noexcept {
return dense_.begin(); return dense_.begin();
@@ -424,7 +395,8 @@ namespace ecs_hpp
const std::size_t vi = indexer_(v); const std::size_t vi = indexer_(v);
const std::size_t dense_index = sparse_[vi]; const std::size_t dense_index = sparse_[vi];
if ( dense_index != dense_.size() - 1 ) { if ( dense_index != dense_.size() - 1 ) {
dense_[dense_index] = std::move(dense_.back()); using std::swap;
swap(dense_[dense_index], dense_.back());
sparse_[indexer_(dense_[dense_index])] = dense_index; sparse_[indexer_(dense_[dense_index])] = dense_index;
} }
dense_.pop_back(); dense_.pop_back();
@@ -508,10 +480,6 @@ namespace ecs_hpp
public: public:
using iterator = typename std::vector<K>::iterator; using iterator = typename std::vector<K>::iterator;
using const_iterator = typename std::vector<K>::const_iterator; using const_iterator = typename std::vector<K>::const_iterator;
public:
static_assert(
std::is_nothrow_move_assignable<T>::value,
"unsupported sparse_map value type");
public: public:
iterator begin() noexcept { iterator begin() noexcept {
return keys_.begin(); return keys_.begin();
@@ -589,7 +557,8 @@ namespace ecs_hpp
return false; return false;
} }
if ( value_index_p.first != values_.size() - 1 ) { if ( value_index_p.first != values_.size() - 1 ) {
values_[value_index_p.first] = std::move(values_.back()); using std::swap;
swap(values_[value_index_p.first], values_.back());
} }
values_.pop_back(); values_.pop_back();
keys_.unordered_erase(k); keys_.unordered_erase(k);
@@ -693,7 +662,7 @@ namespace ecs_hpp
virtual std::size_t memory_usage() const noexcept = 0; virtual std::size_t memory_usage() const noexcept = 0;
}; };
template < typename T, bool E = std::is_empty<T>::value > template < typename T, bool E = std::is_empty_v<T> >
class component_storage final : public component_storage_base { class component_storage final : public component_storage_base {
public: public:
component_storage(registry& owner) component_storage(registry& owner)
@@ -702,11 +671,11 @@ namespace ecs_hpp
template < typename... Args > template < typename... Args >
T& assign(entity_id id, Args&&... args) { T& assign(entity_id id, Args&&... args) {
if ( T* value = components_.find(id) ) { if ( T* value = components_.find(id) ) {
*value = T(std::forward<Args>(args)...); *value = T{std::forward<Args>(args)...};
return *value; return *value;
} }
assert(!components_locker_.is_locked()); assert(!components_locker_.is_locked());
return *components_.insert(id, T(std::forward<Args>(args)...)).first; return *components_.insert(id, T{std::forward<Args>(args)...}).first;
} }
template < typename... Args > template < typename... Args >
@@ -715,7 +684,7 @@ namespace ecs_hpp
return *value; return *value;
} }
assert(!components_locker_.is_locked()); assert(!components_locker_.is_locked());
return *components_.insert(id, T(std::forward<Args>(args)...)).first; return *components_.insert(id, T{std::forward<Args>(args)...}).first;
} }
bool exists(entity_id id) const noexcept { bool exists(entity_id id) const noexcept {
@@ -751,8 +720,7 @@ namespace ecs_hpp
} }
void clone(entity_id from, entity_id to) override { void clone(entity_id from, entity_id to) override {
const T* c = find(from); if ( const T* c = find(from) ) {
if ( c ) {
assign(to, *c); assign(to, *c);
} }
} }
@@ -845,8 +813,7 @@ namespace ecs_hpp
} }
void clone(entity_id from, entity_id to) override { void clone(entity_id from, entity_id to) override {
const T* c = find(from); if ( const T* c = find(from) ) {
if ( c ) {
assign(to, *c); assign(to, *c);
} }
} }
@@ -1378,20 +1345,20 @@ namespace ecs_hpp
std::size_t entity_count() const noexcept; std::size_t entity_count() const noexcept;
std::size_t entity_component_count(const const_uentity& ent) const noexcept; std::size_t entity_component_count(const const_uentity& ent) const noexcept;
template < typename F > template < typename F, typename... Opts >
void for_each_entity(F&& f); void for_each_entity(F&& f, Opts&&... opts);
template < typename F > template < typename F, typename... Opts >
void for_each_entity(F&& f) const; void for_each_entity(F&& f, Opts&&... opts) const;
template < typename T, typename F > template < typename T, typename F, typename... Opts >
void for_each_component(F&& f); void for_each_component(F&& f, Opts&&... opts);
template < typename T, typename F > template < typename T, typename F, typename... Opts >
void for_each_component(F&& f) const; void for_each_component(F&& f, Opts&&... opts) const;
template < typename... Ts, typename F > template < typename... Ts, typename F, typename... Opts >
void for_joined_components(F&& f); void for_joined_components(F&& f, Opts&&... opts);
template < typename... Ts, typename F > template < typename... Ts, typename F, typename... Opts >
void for_joined_components(F&& f) const; void for_joined_components(F&& f, Opts&&... opts) const;
template < typename T, typename... Args > template < typename T, typename... Args >
void add_system(priority_t priority, Args&&... args); void add_system(priority_t priority, Args&&... args);
@@ -1422,20 +1389,24 @@ namespace ecs_hpp
template < typename T template < typename T
, typename... Ts , typename... Ts
, typename F , typename F
, typename... Opts
, std::size_t I , std::size_t I
, std::size_t... Is > , std::size_t... Is >
void for_joined_components_impl_( void for_joined_components_impl_(
std::index_sequence<I, Is...>,
F&& f, F&& f,
std::index_sequence<I, Is...> iseq); Opts&&... opts);
template < typename T template < typename T
, typename... Ts , typename... Ts
, typename F , typename F
, typename... Opts
, std::size_t I , std::size_t I
, std::size_t... Is > , std::size_t... Is >
void for_joined_components_impl_( void for_joined_components_impl_(
std::index_sequence<I, Is...>,
F&& f, F&& f,
std::index_sequence<I, Is...> iseq) const; Opts&&... opts) const;
template < typename T template < typename T
, typename... Ts , typename... Ts
@@ -1486,6 +1457,56 @@ namespace ecs_hpp
}; };
} }
// -----------------------------------------------------------------------------
//
// filter
//
// -----------------------------------------------------------------------------
namespace ecs_hpp
{
template < typename... Ts >
class filter_any final {
public:
bool operator()(const const_entity& e) const noexcept {
return !(... || e.exists_component<Ts>());
}
};
template < typename... Ts >
class filter_all final {
public:
bool operator()(const const_entity& e) const noexcept {
return !(... && e.exists_component<Ts>());
}
};
}
// -----------------------------------------------------------------------------
//
// require
//
// -----------------------------------------------------------------------------
namespace ecs_hpp
{
template < typename... Ts >
class require_any final {
public:
bool operator()(const const_entity& e) const noexcept {
return (... || e.exists_component<Ts>());
}
};
template < typename... Ts >
class require_all final {
public:
bool operator()(const const_entity& e) const noexcept {
return (... && e.exists_component<Ts>());
}
};
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// //
// fillers // fillers
@@ -1561,7 +1582,7 @@ namespace ecs_hpp
} }
inline bool entity::valid() const noexcept { inline bool entity::valid() const noexcept {
return detail::as_const(*owner_).valid_entity(id_); return std::as_const(*owner_).valid_entity(id_);
} }
template < typename T, typename... Args > template < typename T, typename... Args >
@@ -1585,7 +1606,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
bool entity::exists_component() const noexcept { bool entity::exists_component() const noexcept {
return detail::as_const(*owner_).exists_component<T>(id_); return std::as_const(*owner_).exists_component<T>(id_);
} }
inline std::size_t entity::remove_all_components() noexcept { inline std::size_t entity::remove_all_components() noexcept {
@@ -1599,7 +1620,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T& entity::get_component() const { const T& entity::get_component() const {
return detail::as_const(*owner_).get_component<T>(id_); return std::as_const(*owner_).get_component<T>(id_);
} }
template < typename T > template < typename T >
@@ -1609,7 +1630,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T* entity::find_component() const noexcept { const T* entity::find_component() const noexcept {
return detail::as_const(*owner_).find_component<T>(id_); return std::as_const(*owner_).find_component<T>(id_);
} }
template < typename... Ts > template < typename... Ts >
@@ -1619,7 +1640,7 @@ namespace ecs_hpp
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts&...> entity::get_components() const { std::tuple<const Ts&...> entity::get_components() const {
return detail::as_const(*owner_).get_components<Ts...>(id_); return std::as_const(*owner_).get_components<Ts...>(id_);
} }
template < typename... Ts > template < typename... Ts >
@@ -1629,11 +1650,11 @@ namespace ecs_hpp
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> entity::find_components() const noexcept { std::tuple<const Ts*...> entity::find_components() const noexcept {
return detail::as_const(*owner_).find_components<Ts...>(id_); return std::as_const(*owner_).find_components<Ts...>(id_);
} }
inline std::size_t entity::component_count() const noexcept { inline std::size_t entity::component_count() const noexcept {
return detail::as_const(*owner_).entity_component_count(id_); return std::as_const(*owner_).entity_component_count(id_);
} }
inline bool operator<(const entity& l, const entity& r) noexcept { inline bool operator<(const entity& l, const entity& r) noexcept {
@@ -1797,7 +1818,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T& component<T>::get() const { const T& component<T>::get() const {
return detail::as_const(owner_).template get_component<T>(); return std::as_const(owner_).template get_component<T>();
} }
template < typename T > template < typename T >
@@ -1807,7 +1828,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T* component<T>::find() const noexcept { const T* component<T>::find() const noexcept {
return detail::as_const(owner_).template find_component<T>(); return std::as_const(owner_).template find_component<T>();
} }
template < typename T > template < typename T >
@@ -1884,17 +1905,17 @@ namespace ecs_hpp
template < typename T > template < typename T >
bool const_component<T>::exists() const noexcept { bool const_component<T>::exists() const noexcept {
return detail::as_const(owner_).template exists_component<T>(); return std::as_const(owner_).template exists_component<T>();
} }
template < typename T > template < typename T >
const T& const_component<T>::get() const { const T& const_component<T>::get() const {
return detail::as_const(owner_).template get_component<T>(); return std::as_const(owner_).template get_component<T>();
} }
template < typename T > template < typename T >
const T* const_component<T>::find() const noexcept { const T* const_component<T>::find() const noexcept {
return detail::as_const(owner_).template find_component<T>(); return std::as_const(owner_).template find_component<T>();
} }
template < typename T > template < typename T >
@@ -1963,7 +1984,7 @@ namespace ecs_hpp
template < typename T, typename... Args > template < typename T, typename... Args >
void typed_applier_with_args<T, Args...>::apply_to_entity(entity& ent, bool override) const { void typed_applier_with_args<T, Args...>::apply_to_entity(entity& ent, bool override) const {
detail::tiny_tuple_apply([&ent, override](const Args&... args){ std::apply([&ent, override](const Args&... args){
if ( override || !ent.exists_component<T>() ) { if ( override || !ent.exists_component<T>() ) {
ent.assign_component<T>(args...); ent.assign_component<T>(args...);
} }
@@ -1972,8 +1993,8 @@ namespace ecs_hpp
template < typename T, typename... Args > template < typename T, typename... Args >
void typed_applier_with_args<T, Args...>::apply_to_component(T& component) const { void typed_applier_with_args<T, Args...>::apply_to_component(T& component) const {
detail::tiny_tuple_apply([&component](const Args&... args){ std::apply([&component](const Args&... args){
component = T(args...); component = T{args...};
}, args_); }, args_);
} }
} }
@@ -2319,8 +2340,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
T& registry::get_component(const uentity& ent) { T& registry::get_component(const uentity& ent) {
assert(valid_entity(ent)); assert(valid_entity(ent));
T* component = find_component<T>(ent); if ( T* component = find_component<T>(ent) ) {
if ( component ) {
return *component; return *component;
} }
throw std::logic_error("ecs_hpp::registry (component not found)"); throw std::logic_error("ecs_hpp::registry (component not found)");
@@ -2329,8 +2349,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T& registry::get_component(const const_uentity& ent) const { const T& registry::get_component(const const_uentity& ent) const {
assert(valid_entity(ent)); assert(valid_entity(ent));
const T* component = find_component<T>(ent); if ( const T* component = find_component<T>(ent) ) {
if ( component ) {
return *component; return *component;
} }
throw std::logic_error("ecs_hpp::registry (component not found)"); throw std::logic_error("ecs_hpp::registry (component not found)");
@@ -2405,54 +2424,62 @@ namespace ecs_hpp
return component_count; return component_count;
} }
template < typename F > template < typename F, typename... Opts >
void registry::for_each_entity(F&& f) { void registry::for_each_entity(F&& f, Opts&&... opts) {
detail::incremental_lock_guard lock(entity_ids_locker_); detail::incremental_lock_guard lock(entity_ids_locker_);
for ( const auto id : entity_ids_ ) { for ( const auto e : entity_ids_ ) {
f({*this, id}); if ( uentity ent{*this, e}; (... && opts(ent)) ) {
f(ent);
}
} }
} }
template < typename F > template < typename F, typename... Opts >
void registry::for_each_entity(F&& f) const { void registry::for_each_entity(F&& f, Opts&&... opts) const {
detail::incremental_lock_guard lock(entity_ids_locker_); detail::incremental_lock_guard lock(entity_ids_locker_);
for ( const auto id : entity_ids_ ) { for ( const auto e : entity_ids_ ) {
f({*this, id}); if ( const_uentity ent{*this, e}; (... && opts(ent)) ) {
f(ent);
}
} }
} }
template < typename T, typename F > template < typename T, typename F, typename... Opts >
void registry::for_each_component(F&& f) { void registry::for_each_component(F&& f, Opts&&... opts) {
detail::component_storage<T>* storage = find_storage_<T>(); if ( detail::component_storage<T>* storage = find_storage_<T>() ) {
if ( storage ) { storage->for_each_component([this, &f, &opts...](const entity_id e, T& t){
storage->for_each_component([this, &f](const entity_id e, T& t){ if ( uentity ent{*this, e}; (... && opts(ent)) ) {
f(uentity{*this, e}, t); f(ent, t);
}
}); });
} }
} }
template < typename T, typename F > template < typename T, typename F, typename... Opts >
void registry::for_each_component(F&& f) const { void registry::for_each_component(F&& f, Opts&&... opts) const {
const detail::component_storage<T>* storage = find_storage_<T>(); if ( const detail::component_storage<T>* storage = find_storage_<T>() ) {
if ( storage ) { storage->for_each_component([this, &f, &opts...](const entity_id e, const T& t){
storage->for_each_component([this, &f](const entity_id e, const T& t){ if ( const_uentity ent{*this, e}; (... && opts(ent)) ) {
f(const_uentity{*this, e}, t); f(ent, t);
}
}); });
} }
} }
template < typename... Ts, typename F > template < typename... Ts, typename F, typename... Opts >
void registry::for_joined_components(F&& f) { void registry::for_joined_components(F&& f, Opts&&... opts) {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
std::make_index_sequence<sizeof...(Ts)>(),
std::forward<F>(f), std::forward<F>(f),
std::make_index_sequence<sizeof...(Ts)>()); std::forward<Opts>(opts)...);
} }
template < typename... Ts, typename F > template < typename... Ts, typename F, typename... Opts >
void registry::for_joined_components(F&& f) const { void registry::for_joined_components(F&& f, Opts&&... opts) const {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
std::make_index_sequence<sizeof...(Ts)>(),
std::forward<F>(f), std::forward<F>(f),
std::make_index_sequence<sizeof...(Ts)>()); std::forward<Opts>(opts)...);
} }
template < typename T, typename... Args > template < typename T, typename... Args >
@@ -2536,8 +2563,7 @@ namespace ecs_hpp
template < typename T > template < typename T >
detail::component_storage<T>& registry::get_or_create_storage_() { detail::component_storage<T>& registry::get_or_create_storage_() {
detail::component_storage<T>* storage = find_storage_<T>(); if ( detail::component_storage<T>* storage = find_storage_<T>() ) {
if ( storage ) {
return *storage; return *storage;
} }
const auto family = detail::type_family<T>::id(); const auto family = detail::type_family<T>::id();
@@ -2551,37 +2577,41 @@ namespace ecs_hpp
template < typename T template < typename T
, typename... Ts , typename... Ts
, typename F , typename F
, typename... Opts
, std::size_t I , std::size_t I
, std::size_t... Is > , std::size_t... Is >
void registry::for_joined_components_impl_( void registry::for_joined_components_impl_(
std::index_sequence<I, Is...>,
F&& f, F&& f,
std::index_sequence<I, Is...> iseq) Opts&&... opts)
{ {
(void)iseq;
const auto ss = std::make_tuple(find_storage_<Ts>()...); const auto ss = std::make_tuple(find_storage_<Ts>()...);
if ( !detail::tuple_contains(ss, nullptr) ) { if ( detail::tuple_contains(ss, nullptr) ) {
for_each_component<T>([this, &f, &ss](const uentity& e, T& t) { return;
for_joined_components_impl_<Ts...>(e, f, ss, t);
});
} }
for_each_component<T>([this, &f, &ss](const uentity& e, T& t) {
for_joined_components_impl_<Ts...>(e, f, ss, t);
}, std::forward<Opts>(opts)...);
} }
template < typename T template < typename T
, typename... Ts , typename... Ts
, typename F , typename F
, typename... Opts
, std::size_t I , std::size_t I
, std::size_t... Is > , std::size_t... Is >
void registry::for_joined_components_impl_( void registry::for_joined_components_impl_(
std::index_sequence<I, Is...>,
F&& f, F&& f,
std::index_sequence<I, Is...> iseq) const Opts&&... opts) const
{ {
(void)iseq;
const auto ss = std::make_tuple(find_storage_<Ts>()...); const auto ss = std::make_tuple(find_storage_<Ts>()...);
if ( !detail::tuple_contains(ss, nullptr) ) { if ( detail::tuple_contains(ss, nullptr) ) {
for_each_component<T>([this, &f, &ss](const const_uentity& e, const T& t) { return;
detail::as_const(*this).for_joined_components_impl_<Ts...>(e, f, ss, t);
});
} }
for_each_component<T>([this, &f, &ss](const const_uentity& e, const T& t) {
std::as_const(*this).for_joined_components_impl_<Ts...>(e, f, ss, t);
}, std::forward<Opts>(opts)...);
} }
template < typename T template < typename T
@@ -2595,8 +2625,7 @@ namespace ecs_hpp
const Ss& ss, const Ss& ss,
Cs&... cs) Cs&... cs)
{ {
T* c = std::get<0>(ss)->find(e); if ( T* c = std::get<0>(ss)->find(e) ) {
if ( c ) {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
e, e,
f, f,
@@ -2617,8 +2646,7 @@ namespace ecs_hpp
const Ss& ss, const Ss& ss,
const Cs&... cs) const const Cs&... cs) const
{ {
const T* c = std::get<0>(ss)->find(e); if ( const T* c = std::get<0>(ss)->find(e) ) {
if ( c ) {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
e, e,
f, f,

View File

@@ -27,9 +27,11 @@ namespace
velocity_c(int nx, int ny) : x(nx), y(ny) {} velocity_c(int nx, int ny) : x(nx), y(ny) {}
}; };
struct movable_c { struct movable_c{};
}; struct disabled_c{};
static_assert(std::is_empty<movable_c>::value, "!!!");
static_assert(std::is_empty_v<movable_c>, "!!!");
static_assert(std::is_empty_v<disabled_c>, "!!!");
bool operator==(const position_c& l, const position_c& r) noexcept { bool operator==(const position_c& l, const position_c& r) noexcept {
return l.x == r.x return l.x == r.x
@@ -203,9 +205,9 @@ TEST_CASE("detail") {
REQUIRE_FALSE(m.size()); REQUIRE_FALSE(m.size());
REQUIRE_FALSE(m.has(42u)); REQUIRE_FALSE(m.has(42u));
REQUIRE_THROWS(m.get(42u)); REQUIRE_THROWS(m.get(42u));
REQUIRE_THROWS(as_const(m).get(42u)); REQUIRE_THROWS(std::as_const(m).get(42u));
REQUIRE_FALSE(m.find(42u)); REQUIRE_FALSE(m.find(42u));
REQUIRE_FALSE(as_const(m).find(42u)); REQUIRE_FALSE(std::as_const(m).find(42u));
{ {
obj_t o{21u}; obj_t o{21u};
@@ -233,20 +235,20 @@ TEST_CASE("detail") {
REQUIRE(m.get(21u).x == 21u); REQUIRE(m.get(21u).x == 21u);
REQUIRE(m.get(42u).x == 42u); REQUIRE(m.get(42u).x == 42u);
REQUIRE(m.get(84u).x == 84u); REQUIRE(m.get(84u).x == 84u);
REQUIRE(as_const(m).get(84u).x == 84u); REQUIRE(std::as_const(m).get(84u).x == 84u);
REQUIRE_THROWS(m.get(11u)); REQUIRE_THROWS(m.get(11u));
REQUIRE_THROWS(m.get(25u)); REQUIRE_THROWS(m.get(25u));
REQUIRE_THROWS(m.get(99u)); REQUIRE_THROWS(m.get(99u));
REQUIRE_THROWS(as_const(m).get(99u)); REQUIRE_THROWS(std::as_const(m).get(99u));
REQUIRE(m.find(21u)->x == 21u); REQUIRE(m.find(21u)->x == 21u);
REQUIRE(m.find(42u)->x == 42u); REQUIRE(m.find(42u)->x == 42u);
REQUIRE(m.find(84u)->x == 84u); REQUIRE(m.find(84u)->x == 84u);
REQUIRE(as_const(m).find(84u)->x == 84u); REQUIRE(std::as_const(m).find(84u)->x == 84u);
REQUIRE_FALSE(m.find(11u)); REQUIRE_FALSE(m.find(11u));
REQUIRE_FALSE(m.find(25u)); REQUIRE_FALSE(m.find(25u));
REQUIRE_FALSE(m.find(99u)); REQUIRE_FALSE(m.find(99u));
REQUIRE_FALSE(as_const(m).find(99u)); REQUIRE_FALSE(std::as_const(m).find(99u));
REQUIRE(m.unordered_erase(42u)); REQUIRE(m.unordered_erase(42u));
REQUIRE_FALSE(m.unordered_erase(42u)); REQUIRE_FALSE(m.unordered_erase(42u));
@@ -527,43 +529,43 @@ TEST_CASE("registry") {
ecs::const_component<position_c> c2 = w.wrap_component<position_c>(e1); ecs::const_component<position_c> c2 = w.wrap_component<position_c>(e1);
REQUIRE_FALSE(c1); REQUIRE_FALSE(c1);
REQUIRE_FALSE(as_const(c1)); REQUIRE_FALSE(std::as_const(c1));
REQUIRE_FALSE(c2); REQUIRE_FALSE(c2);
REQUIRE_FALSE(as_const(c2)); REQUIRE_FALSE(std::as_const(c2));
REQUIRE_THROWS_AS(*c1, std::logic_error); REQUIRE_THROWS_AS(*c1, std::logic_error);
REQUIRE_THROWS_AS(*as_const(c1), std::logic_error); REQUIRE_THROWS_AS(*std::as_const(c1), std::logic_error);
REQUIRE_THROWS_AS(*c2, std::logic_error); REQUIRE_THROWS_AS(*c2, std::logic_error);
REQUIRE_THROWS_AS(*as_const(c2), std::logic_error); REQUIRE_THROWS_AS(*std::as_const(c2), std::logic_error);
c1.assign(1,2); c1.assign(1,2);
REQUIRE(c1); REQUIRE(c1);
REQUIRE(as_const(c1)); REQUIRE(std::as_const(c1));
REQUIRE(c2); REQUIRE(c2);
REQUIRE(as_const(c2)); REQUIRE(std::as_const(c2));
REQUIRE(*c1 == position_c(1,2)); REQUIRE(*c1 == position_c(1,2));
REQUIRE(*as_const(c1) == position_c(1,2)); REQUIRE(*std::as_const(c1) == position_c(1,2));
REQUIRE(*c2 == position_c(1,2)); REQUIRE(*c2 == position_c(1,2));
REQUIRE(*as_const(c2) == position_c(1,2)); REQUIRE(*std::as_const(c2) == position_c(1,2));
REQUIRE(c1->x == 1); REQUIRE(c1->x == 1);
REQUIRE(c1->y == 2); REQUIRE(c1->y == 2);
REQUIRE(as_const(c1)->x == 1); REQUIRE(std::as_const(c1)->x == 1);
REQUIRE(as_const(c1)->y == 2); REQUIRE(std::as_const(c1)->y == 2);
REQUIRE(c2->x == 1); REQUIRE(c2->x == 1);
REQUIRE(c2->y == 2); REQUIRE(c2->y == 2);
REQUIRE(as_const(c2)->x == 1); REQUIRE(std::as_const(c2)->x == 1);
REQUIRE(as_const(c2)->y == 2); REQUIRE(std::as_const(c2)->y == 2);
c1.remove(); c1.remove();
REQUIRE_FALSE(c1); REQUIRE_FALSE(c1);
REQUIRE_FALSE(as_const(c1)); REQUIRE_FALSE(std::as_const(c1));
REQUIRE_FALSE(c2); REQUIRE_FALSE(c2);
REQUIRE_FALSE(as_const(c2)); REQUIRE_FALSE(std::as_const(c2));
} }
{ {
ecs::registry w; ecs::registry w;
@@ -1174,6 +1176,179 @@ TEST_CASE("registry") {
}); });
} }
} }
SECTION("options") {
{
ecs::registry w;
auto e = w.create_entity();
REQUIRE(ecs::filter<>{}(e));
REQUIRE(ecs::filter<position_c>{}(e));
REQUIRE(ecs::filter<velocity_c>{}(e));
REQUIRE(ecs::filter<position_c, velocity_c>{}(e));
REQUIRE(ecs::filter_any<>{}(e));
REQUIRE(ecs::filter_any<position_c>{}(e));
REQUIRE(ecs::filter_any<velocity_c>{}(e));
REQUIRE(ecs::filter_any<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter_all<>{}(e));
REQUIRE(ecs::filter_all<position_c>{}(e));
REQUIRE(ecs::filter_all<velocity_c>{}(e));
REQUIRE(ecs::filter_all<position_c, velocity_c>{}(e));
e.assign_component<position_c>();
REQUIRE(ecs::filter<>{}(e));
REQUIRE_FALSE(ecs::filter<position_c>{}(e));
REQUIRE(ecs::filter<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter<position_c, velocity_c>{}(e));
REQUIRE(ecs::filter_any<>{}(e));
REQUIRE_FALSE(ecs::filter_any<position_c>{}(e));
REQUIRE(ecs::filter_any<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter_any<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter_all<>{}(e));
REQUIRE_FALSE(ecs::filter_all<position_c>{}(e));
REQUIRE(ecs::filter_all<velocity_c>{}(e));
REQUIRE(ecs::filter_all<position_c, velocity_c>{}(e));
e.assign_component<velocity_c>();
REQUIRE(ecs::filter<>{}(e));
REQUIRE_FALSE(ecs::filter<position_c>{}(e));
REQUIRE_FALSE(ecs::filter<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter<position_c, velocity_c>{}(e));
REQUIRE(ecs::filter_any<>{}(e));
REQUIRE_FALSE(ecs::filter_any<position_c>{}(e));
REQUIRE_FALSE(ecs::filter_any<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter_any<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter_all<>{}(e));
REQUIRE_FALSE(ecs::filter_all<position_c>{}(e));
REQUIRE_FALSE(ecs::filter_all<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter_all<position_c, velocity_c>{}(e));
}
{
ecs::registry w;
auto e = w.create_entity();
REQUIRE(ecs::require<>{}(e));
REQUIRE_FALSE(ecs::require<position_c>{}(e));
REQUIRE_FALSE(ecs::require<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<>{}(e));
REQUIRE_FALSE(ecs::require_any<position_c>{}(e));
REQUIRE_FALSE(ecs::require_any<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<position_c, velocity_c>{}(e));
REQUIRE(ecs::require_all<>{}(e));
REQUIRE_FALSE(ecs::require_all<position_c>{}(e));
REQUIRE_FALSE(ecs::require_all<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_all<position_c, velocity_c>{}(e));
e.assign_component<position_c>();
REQUIRE(ecs::require<>{}(e));
REQUIRE(ecs::require<position_c>{}(e));
REQUIRE_FALSE(ecs::require<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<>{}(e));
REQUIRE(ecs::require_any<position_c>{}(e));
REQUIRE_FALSE(ecs::require_any<velocity_c>{}(e));
REQUIRE(ecs::require_any<position_c, velocity_c>{}(e));
REQUIRE(ecs::require_all<>{}(e));
REQUIRE(ecs::require_all<position_c>{}(e));
REQUIRE_FALSE(ecs::require_all<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_all<position_c, velocity_c>{}(e));
e.assign_component<velocity_c>();
REQUIRE(ecs::require<>{}(e));
REQUIRE(ecs::require<position_c>{}(e));
REQUIRE(ecs::require<velocity_c>{}(e));
REQUIRE(ecs::require<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<>{}(e));
REQUIRE(ecs::require_any<position_c>{}(e));
REQUIRE(ecs::require_any<velocity_c>{}(e));
REQUIRE(ecs::require_any<position_c, velocity_c>{}(e));
REQUIRE(ecs::require_all<>{}(e));
REQUIRE(ecs::require_all<position_c>{}(e));
REQUIRE(ecs::require_all<velocity_c>{}(e));
REQUIRE(ecs::require_all<position_c, velocity_c>{}(e));
}
{
ecs::registry w;
auto e1 = w.create_entity();
e1.assign_component<movable_c>();
e1.assign_component<position_c>(0,0);
e1.assign_component<velocity_c>(1,2);
auto e2 = w.create_entity();
e2.assign_component<position_c>(0,0);
e2.assign_component<velocity_c>(1,2);
w.for_each_component<position_c>([
](ecs::entity, position_c& p){
p = position_c{5,5};
}, ecs::require<movable_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(5,5));
REQUIRE(e2.get_component<position_c>() == position_c(0,0));
w.for_joined_components<position_c, velocity_c>([
](ecs::entity, position_c& p, const velocity_c& v){
p.x += v.x;
p.y += v.y;
}, ecs::filter<movable_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(5,5));
REQUIRE(e2.get_component<position_c>() == position_c(1,2));
e1.assign_component<disabled_c>();
e2.assign_component<movable_c>();
w.for_joined_components<position_c, velocity_c>([
](ecs::entity, position_c& p, const velocity_c& v){
p.x += v.x;
p.y += v.y;
}, ecs::require<movable_c>{}, ecs::filter<disabled_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(5,5));
REQUIRE(e2.get_component<position_c>() == position_c(2,4));
}
{
ecs::registry w;
auto e1 = w.create_entity();
e1.assign_component<position_c>(0,0);
e1.assign_component<velocity_c>(1,2);
auto e2 = w.create_entity();
e2.assign_component<disabled_c>();
e2.assign_component<position_c>(0,0);
e2.assign_component<velocity_c>(1,2);
w.for_each_entity([](ecs::entity e){
position_c& p = e.get_component<position_c>();
const velocity_c& v = e.get_component<velocity_c>();
p.x += v.x;
p.y += v.y;
}, ecs::filter<disabled_c>{}, ecs::require<position_c, velocity_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(1,2));
REQUIRE(e2.get_component<position_c>() == position_c(0,0));
}
}
SECTION("systems") { SECTION("systems") {
{ {
class movement_system : public ecs::system { class movement_system : public ecs::system {
@@ -1396,61 +1571,67 @@ TEST_CASE("registry") {
} }
TEST_CASE("example") { TEST_CASE("example") {
struct position_component { struct movable {};
float x; struct disabled {};
float y;
position_component(float nx, float ny) struct position {
: x(nx), y(ny) {} float x{};
float y{};
}; };
struct velocity_component { struct velocity {
float dx; float dx{};
float dy; float dy{};
velocity_component(float ndx, float ndy)
: dx(ndx), dy(ndy) {}
}; };
class movement_system : public ecs_hpp::system { class movement_system : public ecs::system {
public: public:
void process(ecs_hpp::registry& owner) override { void process(ecs::registry& owner) override {
owner.for_joined_components< owner.for_joined_components<
position_component, position,
velocity_component velocity
>([](const ecs_hpp::entity&, position_component& p, const velocity_component& v) { >([](ecs::entity, position& p, const velocity& v) {
p.x += v.dx; p.x += v.dx;
p.y += v.dy; p.y += v.dy;
}); }, ecs::require<movable>{}, ecs::filter<disabled>{});
} }
}; };
class gravity_system : public ecs_hpp::system { class gravity_system : public ecs::system {
public: public:
gravity_system(float gravity) gravity_system(float gravity)
: gravity_(gravity) {} : gravity_(gravity) {}
void process(ecs_hpp::registry& owner) override { void process(ecs::registry& owner) override {
owner.for_each_component< owner.for_each_component<
velocity_component velocity
>([this](const ecs_hpp::entity&, velocity_component& v) { >([this](ecs::entity, velocity& v) {
v.dx += gravity_; v.dx += gravity_;
v.dy += gravity_; v.dy += gravity_;
}); }, ecs::filter<disabled>{});
} }
private: private:
float gravity_; float gravity_{};
}; };
ecs_hpp::registry world; ecs::registry world;
world.add_system<movement_system>(0);
world.add_system<gravity_system>(1, 9.8f); ecs::registry_filler(world)
.system<movement_system>(0)
.system<gravity_system>(1, 9.8f);
auto entity_one = world.create_entity(); auto entity_one = world.create_entity();
world.assign_component<position_component>(entity_one, 4.f, 2.f); ecs::entity_filler(entity_one)
world.assign_component<velocity_component>(entity_one, 10.f, 20.f); .component<movable>()
.component<position>(4.f, 2.f)
.component<velocity>(10.f, 20.f);
auto entity_two = world.create_entity(); auto entity_two = world.create_entity();
entity_two.assign_component<position_component>(4.f, 2.f); ecs::entity_filler(entity_two)
entity_two.assign_component<velocity_component>(10.f, 20.f); .component<movable>()
.component<disabled>()
.component<position>(4.f, 2.f)
.component<velocity>(10.f, 20.f);
world.process_all_systems(); world.process_all_systems();
} }