mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2025-12-16 22:19:21 +07:00
61
README.md
61
README.md
@@ -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
110
ecs.hpp
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
178
ecs_tests.cpp
178
ecs_tests.cpp
@@ -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();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user