Merge pull request #7 from BlackMATov/dev

Dev
This commit is contained in:
BlackMat MATov
2018-12-28 10:08:21 +07:00
committed by GitHub
3 changed files with 239 additions and 110 deletions

View File

@@ -31,9 +31,66 @@
#include "ecs.hpp" #include "ecs.hpp"
``` ```
## Examples ## Basic usage
> coming soon! ```cpp
struct position_component {
float x{0};
float y{0};
position_component(float nx, float ny)
: x(nx), y(ny) {}
};
struct velocity_component {
float dx{0};
float dy{0};
velocity_component(float ndx, float ndy)
: dx(ndx), dy(ndy) {}
};
class movement_system : public ecs_hpp::system {
public:
void process(ecs_hpp::registry& owner) override {
owner.for_joined_components<
position_component,
velocity_component
>([](const ecs_hpp::entity& e, position_component& p, const velocity_component& v) {
p.x += v.dx;
p.y += v.dy;
});
}
};
class gravity_system : public ecs_hpp::system {
public:
gravity_system(float gravity)
: gravity_(gravity) {}
void process(ecs_hpp::registry& owner) override {
owner.for_each_component<
velocity_component
>([this](const ecs_hpp::entity& e, velocity_component& v) {
v.dx += gravity_;
v.dy += gravity_;
});
}
private:
float gravity_;
};
ecs_hpp::registry world;
world.add_system<movement_system>();
auto entity_one = world.create_entity();
world.assign_component<position_component>(entity_one, 4.f, 2.f);
world.assign_component<velocity_component>(entity_one, 10.f, 20.f);
auto entity_two = world.create_entity();
entity_two.assign_component<position_component>(4.f, 2.f);
entity_two.assign_component<velocity_component>(10.f, 20.f);
world.process_systems();
```
## API ## API

110
ecs.hpp
View File

@@ -13,10 +13,8 @@
#include <tuple> #include <tuple>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <limits>
#include <utility> #include <utility>
#include <iterator> #include <iterator>
#include <exception>
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
@@ -37,35 +35,22 @@ namespace ecs_hpp
using family_id = std::uint16_t; using family_id = std::uint16_t;
using entity_id = std::uint32_t; using entity_id = std::uint32_t;
const std::size_t entity_id_index_bits = 22; constexpr std::size_t entity_id_index_bits = 22u;
const std::size_t entity_id_index_mask = (1 << entity_id_index_bits) - 1; constexpr std::size_t entity_id_version_bits = 10u;
const std::size_t entity_id_version_bits = 10;
const std::size_t entity_id_version_mask = (1 << entity_id_version_bits) - 1;
static_assert( static_assert(
std::is_unsigned<family_id>::value, std::is_unsigned<family_id>::value,
"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<entity_id>::value,
"ecs_hpp::entity_id must be an unsigned integer"); "ecs_hpp (entity_id must be an unsigned integer)");
static_assert( static_assert(
entity_id_index_bits > 0u &&
entity_id_version_bits > 0u &&
sizeof(entity_id) == (entity_id_index_bits + entity_id_version_bits) / 8u, sizeof(entity_id) == (entity_id_index_bits + entity_id_version_bits) / 8u,
"ecs_hpp::entity_id mismatch index and version bits"); "ecs_hpp (invalid entity id index and version bits)");
constexpr inline entity_id entity_id_index(entity_id id) noexcept {
return id & entity_id_index_mask;
}
constexpr inline entity_id entity_id_version(entity_id id) noexcept {
return (id >> entity_id_index_bits) & entity_id_version_mask;
}
constexpr inline entity_id entity_id_join(entity_id index, entity_id version) noexcept {
return index | (version << entity_id_index_bits);
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -144,6 +129,31 @@ namespace ecs_hpp
} }
return tuple_contains(tuple_tail(t), v); return tuple_contains(tuple_tail(t), v);
} }
//
// entity_id index/version
//
constexpr std::size_t entity_id_index_mask = (1u << entity_id_index_bits) - 1u;
constexpr std::size_t entity_id_version_mask = (1u << entity_id_version_bits) - 1u;
constexpr inline entity_id entity_id_index(entity_id id) noexcept {
return id & entity_id_index_mask;
}
constexpr inline entity_id entity_id_version(entity_id id) noexcept {
return (id >> entity_id_index_bits) & entity_id_version_mask;
}
constexpr inline entity_id entity_id_join(entity_id index, entity_id version) noexcept {
return index | (version << entity_id_index_bits);
}
constexpr inline entity_id upgrade_entity_id(entity_id id) noexcept {
return entity_id_join(
entity_id_index(id),
entity_id_version(id) + 1u);
}
} }
} }
@@ -320,15 +330,15 @@ namespace ecs_hpp
: end(); : end();
} }
std::size_t get_index(const T& v) const { std::size_t get_dense_index(const T& v) const {
const auto p = find_index(v); const auto p = find_dense_index(v);
if ( p.second ) { if ( p.second ) {
return p.first; return p.first;
} }
throw std::logic_error("ecs_hpp::sparse_set(value not found)"); throw std::logic_error("ecs_hpp::sparse_set (value not found)");
} }
std::pair<std::size_t,bool> find_index(const T& v) const noexcept { std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept {
return has(v) return has(v)
? std::make_pair(sparse_[indexer_(v)], true) ? std::make_pair(sparse_[indexer_(v)], true)
: std::make_pair(std::size_t(-1), false); : std::make_pair(std::size_t(-1), false);
@@ -474,7 +484,7 @@ namespace ecs_hpp
if ( !keys_.has(k) ) { if ( !keys_.has(k) ) {
return false; return false;
} }
const std::size_t index = keys_.get_index(k); const std::size_t index = keys_.get_dense_index(k);
values_[index] = std::move(values_.back()); values_[index] = std::move(values_.back());
values_.pop_back(); values_.pop_back();
keys_.unordered_erase(k); keys_.unordered_erase(k);
@@ -490,23 +500,23 @@ namespace ecs_hpp
return keys_.has(k); return keys_.has(k);
} }
T& get_value(const K& k) { T& get(const K& k) {
return values_[keys_.get_index(k)]; return values_[keys_.get_dense_index(k)];
} }
const T& get_value(const K& k) const { const T& get(const K& k) const {
return values_[keys_.get_index(k)]; return values_[keys_.get_dense_index(k)];
} }
T* find_value(const K& k) noexcept { T* find(const K& k) noexcept {
const auto ip = keys_.find_index(k); const auto ip = keys_.find_dense_index(k);
return ip.second return ip.second
? &values_[ip.first] ? &values_[ip.first]
: nullptr; : nullptr;
} }
const T* find_value(const K& k) const noexcept { const T* find(const K& k) const noexcept {
const auto ip = keys_.find_index(k); const auto ip = keys_.find_dense_index(k);
return ip.second return ip.second
? &values_[ip.first] ? &values_[ip.first]
: nullptr; : nullptr;
@@ -603,7 +613,7 @@ namespace ecs_hpp
template < typename... Args > template < typename... Args >
void component_storage<T>::assign(entity_id id, Args&&... args) { void component_storage<T>::assign(entity_id id, Args&&... args) {
if ( !components_.emplace(id, std::forward<Args>(args)...) ) { if ( !components_.emplace(id, std::forward<Args>(args)...) ) {
components_.get_value(id) = T(std::forward<Args>(args)...); components_.get(id) = T(std::forward<Args>(args)...);
} }
} }
@@ -619,19 +629,19 @@ namespace ecs_hpp
template < typename T > template < typename T >
T* component_storage<T>::find(entity_id id) noexcept { T* component_storage<T>::find(entity_id id) noexcept {
return components_.find_value(id); return components_.find(id);
} }
template < typename T > template < typename T >
const T* component_storage<T>::find(entity_id id) const noexcept { const T* component_storage<T>::find(entity_id id) const noexcept {
return components_.find_value(id); return components_.find(id);
} }
template < typename T > template < typename T >
template < typename F > template < typename F >
void component_storage<T>::for_each_component(F&& f) noexcept { void component_storage<T>::for_each_component(F&& f) noexcept {
for ( const auto id : components_ ) { for ( const auto id : components_ ) {
f(entity(owner_, id), components_.get_value(id)); f(entity(owner_, id), components_.get(id));
} }
} }
@@ -639,7 +649,7 @@ namespace ecs_hpp
template < typename F > template < typename F >
void component_storage<T>::for_each_component(F&& f) const noexcept { void component_storage<T>::for_each_component(F&& f) const noexcept {
for ( const auto id : components_ ) { for ( const auto id : components_ ) {
f(entity(owner_, id), components_.get_value(id)); f(entity(owner_, id), components_.get(id));
} }
} }
} }
@@ -977,21 +987,19 @@ namespace ecs_hpp
inline entity registry::create_entity() { inline entity registry::create_entity() {
if ( !free_entity_ids_.empty() ) { if ( !free_entity_ids_.empty() ) {
const auto free_ent_id = free_entity_ids_.back(); const auto free_ent_id = free_entity_ids_.back();
const auto new_ent_id = entity_id_join( const auto new_ent_id = detail::upgrade_entity_id(free_ent_id);
entity_id_index(free_ent_id),
entity_id_version(free_ent_id) + 1u);
auto ent = entity(*this, new_ent_id); auto ent = entity(*this, new_ent_id);
entity_ids_.insert(new_ent_id); entity_ids_.insert(new_ent_id);
free_entity_ids_.pop_back(); free_entity_ids_.pop_back();
return ent; return ent;
} }
if ( last_entity_id_ < entity_id_index_mask ) { if ( last_entity_id_ < detail::entity_id_index_mask ) {
auto ent = entity(*this, ++last_entity_id_); auto ent = entity(*this, ++last_entity_id_);
entity_ids_.insert(ent.id()); entity_ids_.insert(ent.id());
return ent; return ent;
} }
throw std::logic_error("ecs_hpp::registry(entity index overlow)"); throw std::logic_error("ecs_hpp::registry (entity index overlow)");
} }
inline bool registry::destroy_entity(const entity& ent) { inline bool registry::destroy_entity(const entity& ent) {
@@ -1050,7 +1058,7 @@ namespace ecs_hpp
if ( component ) { 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)");
} }
template < typename T > template < typename T >
@@ -1059,7 +1067,7 @@ namespace ecs_hpp
if ( component ) { 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)");
} }
template < typename T > template < typename T >
@@ -1139,7 +1147,7 @@ namespace ecs_hpp
const auto family = detail::type_family<T>::id(); const auto family = detail::type_family<T>::id();
using raw_storage_ptr = detail::component_storage<T>*; using raw_storage_ptr = detail::component_storage<T>*;
return storages_.has(family) return storages_.has(family)
? static_cast<raw_storage_ptr>(storages_.get_value(family).get()) ? static_cast<raw_storage_ptr>(storages_.get(family).get())
: nullptr; : nullptr;
} }
@@ -1148,7 +1156,7 @@ namespace ecs_hpp
const auto family = detail::type_family<T>::id(); const auto family = detail::type_family<T>::id();
using raw_storage_ptr = const detail::component_storage<T>*; using raw_storage_ptr = const detail::component_storage<T>*;
return storages_.has(family) return storages_.has(family)
? static_cast<raw_storage_ptr>(storages_.get_value(family).get()) ? static_cast<raw_storage_ptr>(storages_.get(family).get())
: nullptr; : nullptr;
} }
@@ -1163,7 +1171,7 @@ namespace ecs_hpp
family, family,
std::make_unique<detail::component_storage<T>>(*this)); std::make_unique<detail::component_storage<T>>(*this));
return *static_cast<detail::component_storage<T>*>( return *static_cast<detail::component_storage<T>*>(
storages_.get_value(family).get()); storages_.get(family).get());
} }
inline bool registry::is_entity_alive_impl_(const entity& ent) const noexcept { inline bool registry::is_entity_alive_impl_(const entity& ent) const noexcept {
@@ -1176,7 +1184,7 @@ namespace ecs_hpp
} }
std::size_t removed_components = 0u; std::size_t removed_components = 0u;
for ( const auto id : storages_ ) { for ( const auto id : storages_ ) {
if ( storages_.get_value(id)->remove(ent.id()) ) { if ( storages_.get(id)->remove(ent.id()) ) {
++removed_components; ++removed_components;
} }
} }

View File

@@ -90,8 +90,8 @@ TEST_CASE("detail") {
REQUIRE(s.capacity() == 0u); REQUIRE(s.capacity() == 0u);
REQUIRE_FALSE(s.has(42u)); REQUIRE_FALSE(s.has(42u));
REQUIRE(s.find(42u) == s.end()); REQUIRE(s.find(42u) == s.end());
REQUIRE_FALSE(s.find_index(42u).second); REQUIRE_FALSE(s.find_dense_index(42u).second);
REQUIRE_THROWS(s.get_index(42u)); REQUIRE_THROWS(s.get_dense_index(42u));
REQUIRE(s.insert(42u)); REQUIRE(s.insert(42u));
@@ -102,9 +102,9 @@ TEST_CASE("detail") {
REQUIRE_FALSE(s.has(84u)); REQUIRE_FALSE(s.has(84u));
REQUIRE(s.find(42u) == s.begin()); REQUIRE(s.find(42u) == s.begin());
REQUIRE(s.find_index(42u).second); REQUIRE(s.find_dense_index(42u).second);
REQUIRE(s.find_index(42u).first == 0u); REQUIRE(s.find_dense_index(42u).first == 0u);
REQUIRE(s.get_index(42u) == 0u); REQUIRE(s.get_dense_index(42u) == 0u);
s.clear(); s.clear();
@@ -129,22 +129,22 @@ TEST_CASE("detail") {
REQUIRE(s.has(42u)); REQUIRE(s.has(42u));
REQUIRE(s.has(84u)); REQUIRE(s.has(84u));
REQUIRE(s.size() == 2u); REQUIRE(s.size() == 2u);
REQUIRE(s.find_index(42u).second); REQUIRE(s.find_dense_index(42u).second);
REQUIRE(s.find_index(42u).first == 0u); REQUIRE(s.find_dense_index(42u).first == 0u);
REQUIRE(s.find_index(84u).second); REQUIRE(s.find_dense_index(84u).second);
REQUIRE(s.find_index(84u).first == 1u); REQUIRE(s.find_dense_index(84u).first == 1u);
REQUIRE(s.get_index(42u) == 0u); REQUIRE(s.get_dense_index(42u) == 0u);
REQUIRE(s.get_index(84u) == 1u); REQUIRE(s.get_dense_index(84u) == 1u);
REQUIRE(s.unordered_erase(42u)); REQUIRE(s.unordered_erase(42u));
REQUIRE_FALSE(s.has(42u)); REQUIRE_FALSE(s.has(42u));
REQUIRE(s.has(84u)); REQUIRE(s.has(84u));
REQUIRE(s.size() == 1u); REQUIRE(s.size() == 1u);
REQUIRE(s.find_index(84u).second); REQUIRE(s.find_dense_index(84u).second);
REQUIRE(s.find_index(84u).first == 0u); REQUIRE(s.find_dense_index(84u).first == 0u);
REQUIRE_THROWS(s.get_index(42u)); REQUIRE_THROWS(s.get_dense_index(42u));
REQUIRE(s.get_index(84u) == 0u); REQUIRE(s.get_dense_index(84u) == 0u);
} }
{ {
sparse_set<position_c, position_c_indexer> s{position_c_indexer()}; sparse_set<position_c, position_c_indexer> s{position_c_indexer()};
@@ -153,14 +153,14 @@ TEST_CASE("detail") {
REQUIRE(s.has(position_c(1,2))); REQUIRE(s.has(position_c(1,2)));
REQUIRE(s.emplace(3,4)); REQUIRE(s.emplace(3,4));
REQUIRE(s.has(position_c(3,4))); REQUIRE(s.has(position_c(3,4)));
REQUIRE(s.get_index(position_c(1,2)) == 0); REQUIRE(s.get_dense_index(position_c(1,2)) == 0);
REQUIRE(s.get_index(position_c(3,4)) == 1); REQUIRE(s.get_dense_index(position_c(3,4)) == 1);
REQUIRE(s.find_index(position_c(1,2)).first == 0); REQUIRE(s.find_dense_index(position_c(1,2)).first == 0);
REQUIRE(s.find_index(position_c(3,4)).first == 1); REQUIRE(s.find_dense_index(position_c(3,4)).first == 1);
REQUIRE(s.find_index(position_c(1,2)).second); REQUIRE(s.find_dense_index(position_c(1,2)).second);
REQUIRE(s.find_index(position_c(3,4)).second); REQUIRE(s.find_dense_index(position_c(3,4)).second);
REQUIRE(s.unordered_erase(position_c(1,2))); REQUIRE(s.unordered_erase(position_c(1,2)));
REQUIRE(s.get_index(position_c(3,4)) == 0); REQUIRE(s.get_dense_index(position_c(3,4)) == 0);
} }
} }
SECTION("sparse_map") { SECTION("sparse_map") {
@@ -177,10 +177,10 @@ TEST_CASE("detail") {
REQUIRE_FALSE(m.size()); REQUIRE_FALSE(m.size());
REQUIRE(m.capacity() == 0u); REQUIRE(m.capacity() == 0u);
REQUIRE_FALSE(m.has(42u)); REQUIRE_FALSE(m.has(42u));
REQUIRE_THROWS(m.get_value(42u)); REQUIRE_THROWS(m.get(42u));
REQUIRE_THROWS(as_const(m).get_value(42u)); REQUIRE_THROWS(as_const(m).get(42u));
REQUIRE_FALSE(m.find_value(42u)); REQUIRE_FALSE(m.find(42u));
REQUIRE_FALSE(as_const(m).find_value(42u)); REQUIRE_FALSE(as_const(m).find(42u));
{ {
obj_t o{21u}; obj_t o{21u};
@@ -206,23 +206,23 @@ TEST_CASE("detail") {
REQUIRE_FALSE(m.has(25u)); REQUIRE_FALSE(m.has(25u));
REQUIRE_FALSE(m.has(99u)); REQUIRE_FALSE(m.has(99u));
REQUIRE(m.get_value(21u).x == 21u); REQUIRE(m.get(21u).x == 21u);
REQUIRE(m.get_value(42u).x == 42u); REQUIRE(m.get(42u).x == 42u);
REQUIRE(m.get_value(84u).x == 84u); REQUIRE(m.get(84u).x == 84u);
REQUIRE(as_const(m).get_value(84u).x == 84u); REQUIRE(as_const(m).get(84u).x == 84u);
REQUIRE_THROWS(m.get_value(11u)); REQUIRE_THROWS(m.get(11u));
REQUIRE_THROWS(m.get_value(25u)); REQUIRE_THROWS(m.get(25u));
REQUIRE_THROWS(m.get_value(99u)); REQUIRE_THROWS(m.get(99u));
REQUIRE_THROWS(as_const(m).get_value(99u)); REQUIRE_THROWS(as_const(m).get(99u));
REQUIRE(m.find_value(21u)->x == 21u); REQUIRE(m.find(21u)->x == 21u);
REQUIRE(m.find_value(42u)->x == 42u); REQUIRE(m.find(42u)->x == 42u);
REQUIRE(m.find_value(84u)->x == 84u); REQUIRE(m.find(84u)->x == 84u);
REQUIRE(as_const(m).find_value(84u)->x == 84u); REQUIRE(as_const(m).find(84u)->x == 84u);
REQUIRE_FALSE(m.find_value(11u)); REQUIRE_FALSE(m.find(11u));
REQUIRE_FALSE(m.find_value(25u)); REQUIRE_FALSE(m.find(25u));
REQUIRE_FALSE(m.find_value(99u)); REQUIRE_FALSE(m.find(99u));
REQUIRE_FALSE(as_const(m).find_value(99u)); REQUIRE_FALSE(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));
@@ -251,14 +251,14 @@ TEST_CASE("detail") {
REQUIRE(s.has(position_c(1,2))); REQUIRE(s.has(position_c(1,2)));
REQUIRE(s.emplace(position_c(3,4), obj_t{3})); REQUIRE(s.emplace(position_c(3,4), obj_t{3}));
REQUIRE(s.has(position_c(3,4))); REQUIRE(s.has(position_c(3,4)));
REQUIRE(s.get_value(position_c(1,2)).x == 1); REQUIRE(s.get(position_c(1,2)).x == 1);
REQUIRE(s.get_value(position_c(3,4)).x == 3); REQUIRE(s.get(position_c(3,4)).x == 3);
REQUIRE(s.find_value(position_c(1,2))->x == 1); REQUIRE(s.find(position_c(1,2))->x == 1);
REQUIRE(s.find_value(position_c(3,4))->x == 3); REQUIRE(s.find(position_c(3,4))->x == 3);
REQUIRE(s.find_value(position_c(1,2))); REQUIRE(s.find(position_c(1,2)));
REQUIRE(s.find_value(position_c(3,4))); REQUIRE(s.find(position_c(3,4)));
REQUIRE(s.unordered_erase(position_c(1,2))); REQUIRE(s.unordered_erase(position_c(1,2)));
REQUIRE(s.get_value(position_c(3,4)).x == 3); REQUIRE(s.get(position_c(3,4)).x == 3);
} }
} }
} }
@@ -301,38 +301,43 @@ TEST_CASE("registry") {
} }
{ {
ecs::registry w; ecs::registry w;
using namespace ecs::detail;
const auto e1 = w.create_entity(); const auto e1 = w.create_entity();
w.destroy_entity(e1); w.destroy_entity(e1);
const auto e2 = w.create_entity(); const auto e2 = w.create_entity();
REQUIRE(e1 != e2); REQUIRE(e1 != e2);
REQUIRE(ecs::entity_id_index(e1.id()) == ecs::entity_id_index(e2.id())); REQUIRE(entity_id_index(e1.id()) == entity_id_index(e2.id()));
REQUIRE(ecs::entity_id_version(e1.id()) + 1 == ecs::entity_id_version(e2.id())); REQUIRE(entity_id_version(e1.id()) + 1 == entity_id_version(e2.id()));
w.destroy_entity(e2); w.destroy_entity(e2);
const auto e3 = w.create_entity(); const auto e3 = w.create_entity();
REQUIRE(e3 != e2); REQUIRE(e3 != e2);
REQUIRE(ecs::entity_id_index(e2.id()) == ecs::entity_id_index(e3.id())); REQUIRE(entity_id_index(e2.id()) == entity_id_index(e3.id()));
REQUIRE(ecs::entity_id_version(e2.id()) + 1 == ecs::entity_id_version(e3.id())); REQUIRE(entity_id_version(e2.id()) + 1 == entity_id_version(e3.id()));
} }
{ {
ecs::registry w; ecs::registry w;
using namespace ecs::detail;
auto e = w.create_entity(); auto e = w.create_entity();
const auto e_id = e.id(); const auto e_id = e.id();
for ( std::size_t i = 0; i < ecs::entity_id_version_mask; ++i ) { for ( std::size_t i = 0; i < entity_id_version_mask; ++i ) {
e.destroy(); e.destroy();
e = w.create_entity(); e = w.create_entity();
REQUIRE(ecs::entity_id_version(e_id) != ecs::entity_id_version(e.id())); REQUIRE(entity_id_version(e_id) != entity_id_version(e.id()));
} }
// entity version wraps around // entity version wraps around
e.destroy(); e.destroy();
e = w.create_entity(); e = w.create_entity();
REQUIRE(ecs::entity_id_version(e_id) == ecs::entity_id_version(e.id())); REQUIRE(entity_id_version(e_id) == entity_id_version(e.id()));
} }
{ {
ecs::registry w; ecs::registry w;
for ( std::size_t i = 0; i < ecs::entity_id_index_mask; ++i ) { using namespace ecs::detail;
for ( std::size_t i = 0; i < entity_id_index_mask; ++i ) {
w.create_entity(); w.create_entity();
} }
// entity index overflow // entity index overflow
@@ -694,3 +699,62 @@ TEST_CASE("registry") {
} }
} }
} }
TEST_CASE("example") {
struct position_component {
float x{0};
float y{0};
position_component(float nx, float ny)
: x(nx), y(ny) {}
};
struct velocity_component {
float dx{0};
float dy{0};
velocity_component(float ndx, float ndy)
: dx(ndx), dy(ndy) {}
};
class movement_system : public ecs_hpp::system {
public:
void process(ecs_hpp::registry& owner) override {
owner.for_joined_components<
position_component,
velocity_component
>([](const ecs_hpp::entity& e, position_component& p, const velocity_component& v) {
p.x += v.dx;
p.y += v.dy;
});
}
};
class gravity_system : public ecs_hpp::system {
public:
gravity_system(float gravity)
: gravity_(gravity) {}
void process(ecs_hpp::registry& owner) override {
owner.for_each_component<
velocity_component
>([this](const ecs_hpp::entity& e, velocity_component& v) {
v.dx += gravity_;
v.dy += gravity_;
});
}
private:
float gravity_;
};
ecs_hpp::registry world;
world.add_system<movement_system>();
auto entity_one = world.create_entity();
world.assign_component<position_component>(entity_one, 4.f, 2.f);
world.assign_component<velocity_component>(entity_one, 10.f, 20.f);
auto entity_two = world.create_entity();
entity_two.assign_component<position_component>(4.f, 2.f);
entity_two.assign_component<velocity_component>(10.f, 20.f);
world.process_systems();
}