component handlers

This commit is contained in:
2019-01-03 06:30:23 +07:00
parent 133f1fb0dc
commit 36f3b43433
2 changed files with 434 additions and 4 deletions

309
ecs.hpp
View File

@@ -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)");
}

View File

@@ -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));
}
}
{