mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2025-12-13 10:35:39 +07:00
component handlers
This commit is contained in:
309
ecs.hpp
309
ecs.hpp
@@ -31,6 +31,11 @@ namespace ecs_hpp
|
||||
class entity;
|
||||
class const_entity;
|
||||
|
||||
template < typename T >
|
||||
class component;
|
||||
template < typename T >
|
||||
class const_component;
|
||||
|
||||
class system;
|
||||
class registry;
|
||||
|
||||
@@ -662,6 +667,9 @@ namespace ecs_hpp
|
||||
{
|
||||
class entity final {
|
||||
public:
|
||||
entity(const entity&) = default;
|
||||
entity& operator=(const entity&) = default;
|
||||
|
||||
entity(registry& owner) noexcept;
|
||||
entity(registry& owner, entity_id id) noexcept;
|
||||
|
||||
@@ -711,7 +719,10 @@ namespace ecs_hpp
|
||||
};
|
||||
|
||||
bool operator==(const entity& l, const entity& r) noexcept;
|
||||
bool operator==(const entity& l, const const_entity& r) noexcept;
|
||||
|
||||
bool operator!=(const entity& l, const entity& r) noexcept;
|
||||
bool operator!=(const entity& l, const const_entity& r) noexcept;
|
||||
}
|
||||
|
||||
namespace std
|
||||
@@ -738,6 +749,9 @@ namespace ecs_hpp
|
||||
{
|
||||
class const_entity final {
|
||||
public:
|
||||
const_entity(const const_entity&) = default;
|
||||
const_entity& operator=(const const_entity&) = default;
|
||||
|
||||
const_entity(const entity& ent) noexcept;
|
||||
|
||||
const_entity(const registry& owner) noexcept;
|
||||
@@ -767,7 +781,10 @@ namespace ecs_hpp
|
||||
entity_id id_{0u};
|
||||
};
|
||||
|
||||
bool operator==(const const_entity& l, const entity& r) noexcept;
|
||||
bool operator==(const const_entity& l, const const_entity& r) noexcept;
|
||||
|
||||
bool operator!=(const const_entity& l, const entity& r) noexcept;
|
||||
bool operator!=(const const_entity& l, const const_entity& r) noexcept;
|
||||
}
|
||||
|
||||
@@ -785,6 +802,113 @@ namespace std
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// component
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace ecs_hpp
|
||||
{
|
||||
template < typename T >
|
||||
class component final {
|
||||
public:
|
||||
component(const component&) = default;
|
||||
component& operator=(const component&) = default;
|
||||
|
||||
component(const entity& owner) noexcept;
|
||||
|
||||
entity& owner() noexcept;
|
||||
const entity& owner() const noexcept;
|
||||
|
||||
bool remove();
|
||||
bool exists() const noexcept;
|
||||
|
||||
template < typename... Args >
|
||||
bool assign(Args&&... args);
|
||||
|
||||
T& get();
|
||||
const T& get() const;
|
||||
|
||||
T* find() noexcept;
|
||||
const T* find() const noexcept;
|
||||
private:
|
||||
entity owner_;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const component<T>& l, const component<T>& r) noexcept;
|
||||
template < typename T >
|
||||
bool operator==(const component<T>& l, const const_component<T>& r) noexcept;
|
||||
|
||||
template < typename T >
|
||||
bool operator!=(const component<T>& l, const component<T>& r) noexcept;
|
||||
template < typename T >
|
||||
bool operator!=(const component<T>& l, const const_component<T>& r) noexcept;
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template < typename T >
|
||||
struct hash<ecs_hpp::component<T>>
|
||||
: std::unary_function<const ecs_hpp::component<T>&, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const ecs_hpp::component<T>& comp) const noexcept {
|
||||
return std::hash<ecs_hpp::entity>()(comp.owner());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// const_component
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace ecs_hpp
|
||||
{
|
||||
template < typename T >
|
||||
class const_component final {
|
||||
public:
|
||||
const_component(const const_component&) = default;
|
||||
const_component& operator=(const const_component&) = default;
|
||||
|
||||
const_component(const component<T>& comp) noexcept;
|
||||
const_component(const const_entity& owner) noexcept;
|
||||
|
||||
const const_entity& owner() const noexcept;
|
||||
|
||||
bool exists() const noexcept;
|
||||
|
||||
const T& get() const;
|
||||
const T* find() const noexcept;
|
||||
private:
|
||||
const_entity owner_;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const const_component<T>& l, const component<T>& r) noexcept;
|
||||
template < typename T >
|
||||
bool operator==(const const_component<T>& l, const const_component<T>& r) noexcept;
|
||||
|
||||
template < typename T >
|
||||
bool operator!=(const const_component<T>& l, const component<T>& r) noexcept;
|
||||
template < typename T >
|
||||
bool operator!=(const const_component<T>& l, const const_component<T>& r) noexcept;
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template < typename T >
|
||||
struct hash<ecs_hpp::const_component<T>>
|
||||
: std::unary_function<const ecs_hpp::const_component<T>&, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const ecs_hpp::const_component<T>& comp) const noexcept {
|
||||
return std::hash<ecs_hpp::const_entity>()(comp.owner());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// system
|
||||
@@ -855,6 +979,14 @@ namespace ecs_hpp
|
||||
registry() = default;
|
||||
~registry() noexcept = default;
|
||||
|
||||
entity wrap_entity(const const_uentity& ent) noexcept;
|
||||
const_entity wrap_entity(const const_uentity& ent) const noexcept;
|
||||
|
||||
template < typename T >
|
||||
component<T> wrap_component(const const_uentity& ent) noexcept;
|
||||
template < typename T >
|
||||
const_component<T> wrap_component(const const_uentity& ent) const noexcept;
|
||||
|
||||
entity create_entity();
|
||||
|
||||
bool destroy_entity(const uentity& ent);
|
||||
@@ -1091,9 +1223,18 @@ namespace ecs_hpp
|
||||
&& l.id() == r.id();
|
||||
}
|
||||
|
||||
inline bool operator==(const entity& l, const const_entity& r) noexcept {
|
||||
return &l.owner() == &r.owner()
|
||||
&& l.id() == r.id();
|
||||
}
|
||||
|
||||
inline bool operator!=(const entity& l, const entity& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
inline bool operator!=(const entity& l, const const_entity& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1152,16 +1293,162 @@ namespace ecs_hpp
|
||||
return (*owner_).find_components<Ts...>(id_);
|
||||
}
|
||||
|
||||
inline bool operator==(const const_entity& l, const entity& r) noexcept {
|
||||
return &l.owner() == &r.owner()
|
||||
&& l.id() == r.id();
|
||||
}
|
||||
|
||||
inline bool operator==(const const_entity& l, const const_entity& r) noexcept {
|
||||
return &l.owner() == &r.owner()
|
||||
&& l.id() == r.id();
|
||||
}
|
||||
|
||||
inline bool operator!=(const const_entity& l, const entity& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
inline bool operator!=(const const_entity& l, const const_entity& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// component impl
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace ecs_hpp
|
||||
{
|
||||
template < typename T >
|
||||
component<T>::component(const entity& owner) noexcept
|
||||
: owner_(owner) {}
|
||||
|
||||
template < typename T >
|
||||
entity& component<T>::owner() noexcept {
|
||||
return owner_;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const entity& component<T>::owner() const noexcept {
|
||||
return owner_;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool component<T>::remove() {
|
||||
return owner_.remove_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool component<T>::exists() const noexcept {
|
||||
return owner_.exists_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
template < typename... Args >
|
||||
bool component<T>::assign(Args&&... args) {
|
||||
return owner_.assign_component<T>(
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
T& component<T>::get() {
|
||||
return owner_.get_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T& component<T>::get() const {
|
||||
return detail::as_const(owner_).template get_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
T* component<T>::find() noexcept {
|
||||
return owner_.find_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T* component<T>::find() const noexcept {
|
||||
return detail::as_const(owner_).template find_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const component<T>& l, const component<T>& r) noexcept {
|
||||
return l.owner() == r.owner();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const component<T>& l, const const_component<T>& r) noexcept {
|
||||
return l.owner() == r.owner();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator!=(const component<T>& l, const component<T>& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator!=(const component<T>& l, const const_component<T>& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// const_component impl
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace ecs_hpp
|
||||
{
|
||||
template < typename T >
|
||||
const_component<T>::const_component(const component<T>& comp) noexcept
|
||||
: owner_(comp.owner()) {}
|
||||
|
||||
template < typename T >
|
||||
const_component<T>::const_component(const const_entity& owner) noexcept
|
||||
: owner_(owner) {}
|
||||
|
||||
template < typename T >
|
||||
const const_entity& const_component<T>::owner() const noexcept {
|
||||
return owner_;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool const_component<T>::exists() const noexcept {
|
||||
return detail::as_const(owner_).template exists_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T& const_component<T>::get() const {
|
||||
return detail::as_const(owner_).template get_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T* const_component<T>::find() const noexcept {
|
||||
return detail::as_const(owner_).template find_component<T>();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const const_component<T>& l, const component<T>& r) noexcept {
|
||||
return l.owner() == r.owner();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const const_component<T>& l, const const_component<T>& r) noexcept {
|
||||
return l.owner() == r.owner();
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator!=(const const_component<T>& l, const component<T>& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator!=(const const_component<T>& l, const const_component<T>& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// registry impl
|
||||
@@ -1263,18 +1550,36 @@ namespace ecs_hpp
|
||||
// registry
|
||||
//
|
||||
|
||||
inline entity registry::wrap_entity(const const_uentity& ent) noexcept {
|
||||
return {*this, ent.id()};
|
||||
}
|
||||
|
||||
inline const_entity registry::wrap_entity(const const_uentity& ent) const noexcept {
|
||||
return {*this, ent.id()};
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
component<T> registry::wrap_component(const const_uentity& ent) noexcept {
|
||||
return {wrap_entity(ent)};
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const_component<T> registry::wrap_component(const const_uentity& ent) const noexcept {
|
||||
return {wrap_entity(ent)};
|
||||
}
|
||||
|
||||
inline entity registry::create_entity() {
|
||||
if ( !free_entity_ids_.empty() ) {
|
||||
const auto free_ent_id = free_entity_ids_.back();
|
||||
const auto new_ent_id = detail::upgrade_entity_id(free_ent_id);
|
||||
entity_ids_.insert(new_ent_id);
|
||||
free_entity_ids_.pop_back();
|
||||
return {*this, new_ent_id};
|
||||
return wrap_entity(new_ent_id);
|
||||
|
||||
}
|
||||
if ( last_entity_id_ < detail::entity_id_index_mask ) {
|
||||
entity_ids_.insert(last_entity_id_ + 1);
|
||||
return {*this, ++last_entity_id_};
|
||||
return wrap_entity(++last_entity_id_);
|
||||
}
|
||||
throw std::logic_error("ecs_hpp::registry (entity index overlow)");
|
||||
}
|
||||
|
||||
129
ecs_tests.cpp
129
ecs_tests.cpp
@@ -285,15 +285,35 @@ TEST_CASE("detail") {
|
||||
|
||||
TEST_CASE("registry") {
|
||||
SECTION("entities") {
|
||||
{
|
||||
ecs::registry w;
|
||||
ecs::entity e1{w};
|
||||
ecs::entity e2 = e1;
|
||||
e2 = e1;
|
||||
|
||||
ecs::const_entity ce1{w};
|
||||
ecs::const_entity ce2 = ce1;
|
||||
ce2 = ce1;
|
||||
|
||||
ecs::const_entity ce3 = e1;
|
||||
ce3 = e2;
|
||||
}
|
||||
{
|
||||
ecs::registry w;
|
||||
|
||||
ecs::entity e1{w};
|
||||
ecs::entity e2{w};
|
||||
ecs::const_entity e3{w};
|
||||
|
||||
REQUIRE(e1 == e2);
|
||||
REQUIRE(e2 == e3);
|
||||
|
||||
REQUIRE_FALSE(e1 != e2);
|
||||
REQUIRE_FALSE(e2 != e3);
|
||||
|
||||
REQUIRE_FALSE(w.alive_entity(e1));
|
||||
REQUIRE_FALSE(w.alive_entity(e2));
|
||||
REQUIRE_FALSE(w.alive_entity(e3));
|
||||
|
||||
REQUIRE_FALSE(w.destroy_entity(e1));
|
||||
REQUIRE_FALSE(w.destroy_entity(e2));
|
||||
@@ -301,12 +321,23 @@ TEST_CASE("registry") {
|
||||
{
|
||||
ecs::registry w;
|
||||
|
||||
auto e1 = w.create_entity();
|
||||
auto e2 = w.create_entity();
|
||||
ecs::entity e1 = w.create_entity();
|
||||
ecs::entity e2 = w.create_entity();
|
||||
ecs::const_entity e3 = w.create_entity();
|
||||
ecs::entity ee3 = w.wrap_entity(e3);
|
||||
|
||||
REQUIRE(e1 != e2);
|
||||
REQUIRE(e2 != e3);
|
||||
REQUIRE_FALSE(e3 != ee3);
|
||||
|
||||
REQUIRE_FALSE(e1 == e2);
|
||||
REQUIRE_FALSE(e2 == e3);
|
||||
REQUIRE(e3 == ee3);
|
||||
|
||||
REQUIRE(w.alive_entity(e1));
|
||||
REQUIRE(w.alive_entity(e2));
|
||||
REQUIRE(w.alive_entity(e3));
|
||||
REQUIRE(w.alive_entity(ee3));
|
||||
|
||||
REQUIRE(w.destroy_entity(e1));
|
||||
REQUIRE_FALSE(w.alive_entity(e1));
|
||||
@@ -316,8 +347,13 @@ TEST_CASE("registry") {
|
||||
REQUIRE_FALSE(w.alive_entity(e1));
|
||||
REQUIRE_FALSE(w.alive_entity(e2));
|
||||
|
||||
REQUIRE(w.destroy_entity(ee3));
|
||||
REQUIRE_FALSE(w.alive_entity(e3));
|
||||
REQUIRE_FALSE(w.alive_entity(ee3));
|
||||
|
||||
REQUIRE_FALSE(w.destroy_entity(e1));
|
||||
REQUIRE_FALSE(w.destroy_entity(e2));
|
||||
REQUIRE_FALSE(w.destroy_entity(ee3));
|
||||
}
|
||||
{
|
||||
ecs::registry w;
|
||||
@@ -364,6 +400,92 @@ TEST_CASE("registry") {
|
||||
REQUIRE_THROWS_AS(w.create_entity(), std::logic_error);
|
||||
}
|
||||
}
|
||||
SECTION("components") {
|
||||
{
|
||||
ecs::registry w;
|
||||
ecs::entity e1 = w.create_entity();
|
||||
ecs::entity e2 = w.create_entity();
|
||||
|
||||
{
|
||||
REQUIRE(w.wrap_component<position_c>(e1) == ecs::component<position_c>(e1));
|
||||
REQUIRE_FALSE(w.wrap_component<position_c>(e1) == ecs::component<position_c>(e2));
|
||||
}
|
||||
{
|
||||
const ecs::registry& ww = w;
|
||||
REQUIRE(ww.wrap_component<position_c>(e1) == ecs::component<position_c>(e1));
|
||||
REQUIRE_FALSE(ww.wrap_component<position_c>(e1) == ecs::component<position_c>(e2));
|
||||
}
|
||||
|
||||
{
|
||||
ecs::component<position_c> c1{e1};
|
||||
REQUIRE_FALSE(c1.exists());
|
||||
}
|
||||
}
|
||||
{
|
||||
ecs::registry w;
|
||||
ecs::const_entity e1 = w.create_entity();
|
||||
ecs::const_entity e2 = w.create_entity();
|
||||
|
||||
{
|
||||
REQUIRE(w.wrap_component<position_c>(e1) == ecs::const_component<position_c>(e1));
|
||||
REQUIRE_FALSE(w.wrap_component<position_c>(e1) == ecs::const_component<position_c>(e2));
|
||||
}
|
||||
}
|
||||
{
|
||||
ecs::registry w;
|
||||
ecs::entity e1 = w.create_entity();
|
||||
|
||||
ecs::component<position_c> c1 = w.wrap_component<position_c>(e1);
|
||||
ecs::const_component<position_c> c2 = w.wrap_component<position_c>(e1);
|
||||
REQUIRE(c1 == c2);
|
||||
REQUIRE_FALSE(c1 != c2);
|
||||
|
||||
REQUIRE(c1.owner() == e1);
|
||||
REQUIRE(c2.owner() == e1);
|
||||
|
||||
REQUIRE_FALSE(c1.exists());
|
||||
REQUIRE_FALSE(c2.exists());
|
||||
REQUIRE_FALSE(c1.find());
|
||||
REQUIRE_FALSE(c2.find());
|
||||
REQUIRE_THROWS_AS(c1.get(), std::logic_error);
|
||||
REQUIRE_THROWS_AS(c2.get(), std::logic_error);
|
||||
|
||||
REQUIRE(c1.assign(4,2));
|
||||
|
||||
REQUIRE(c1.exists());
|
||||
REQUIRE(c2.exists());
|
||||
REQUIRE(c1.find()->x == 4);
|
||||
REQUIRE(c1.find()->y == 2);
|
||||
REQUIRE(c2.find()->x == 4);
|
||||
REQUIRE(c2.find()->y == 2);
|
||||
REQUIRE(c1.get().x == 4);
|
||||
REQUIRE(c1.get().y == 2);
|
||||
REQUIRE(c2.get().x == 4);
|
||||
REQUIRE(c2.get().y == 2);
|
||||
|
||||
REQUIRE(c1.assign(2,4));
|
||||
|
||||
REQUIRE(c1.find()->x == 2);
|
||||
REQUIRE(c1.find()->y == 4);
|
||||
REQUIRE(c2.find()->x == 2);
|
||||
REQUIRE(c2.find()->y == 4);
|
||||
REQUIRE(c1.get().x == 2);
|
||||
REQUIRE(c1.get().y == 4);
|
||||
REQUIRE(c2.get().x == 2);
|
||||
REQUIRE(c2.get().y == 4);
|
||||
|
||||
REQUIRE(c1.remove());
|
||||
|
||||
REQUIRE_FALSE(c1.exists());
|
||||
REQUIRE_FALSE(c2.exists());
|
||||
REQUIRE_FALSE(c1.find());
|
||||
REQUIRE_FALSE(c2.find());
|
||||
REQUIRE_THROWS_AS(c1.get(), std::logic_error);
|
||||
REQUIRE_THROWS_AS(c2.get(), std::logic_error);
|
||||
|
||||
REQUIRE_FALSE(c1.remove());
|
||||
}
|
||||
}
|
||||
SECTION("component_assigning") {
|
||||
{
|
||||
ecs::registry w;
|
||||
@@ -418,6 +540,9 @@ TEST_CASE("registry") {
|
||||
|
||||
REQUIRE_FALSE(e1.exists_component<position_c>());
|
||||
REQUIRE_FALSE(e1.exists_component<velocity_c>());
|
||||
REQUIRE_FALSE(w.component_count<position_c>());
|
||||
REQUIRE_FALSE(w.component_count<velocity_c>());
|
||||
REQUIRE_FALSE(w.entity_component_count<position_c>(e1));
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user