mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2025-12-15 11:53:51 +07:00
component access
This commit is contained in:
130
ecs.hpp
130
ecs.hpp
@@ -14,6 +14,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@@ -100,6 +102,8 @@ namespace ecs_hpp
|
|||||||
void assign(entity_id id, Args&&... args);
|
void assign(entity_id id, Args&&... args);
|
||||||
bool remove(entity_id id) noexcept override;
|
bool remove(entity_id id) noexcept override;
|
||||||
bool exists(entity_id id) const noexcept override;
|
bool exists(entity_id id) const noexcept override;
|
||||||
|
T* find(entity_id id) noexcept;
|
||||||
|
const T* find(entity_id id) const noexcept;
|
||||||
private:
|
private:
|
||||||
std::unordered_map<entity_id, T> components_;
|
std::unordered_map<entity_id, T> components_;
|
||||||
};
|
};
|
||||||
@@ -119,9 +123,40 @@ namespace ecs_hpp
|
|||||||
bool component_storage<T>::exists(entity_id id) const noexcept {
|
bool component_storage<T>::exists(entity_id id) const noexcept {
|
||||||
return components_.find(id) != components_.end();
|
return components_.find(id) != components_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T* component_storage<T>::find(entity_id id) noexcept {
|
||||||
|
const auto iter = components_.find(id);
|
||||||
|
return iter != components_.end()
|
||||||
|
? &iter->second
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T* component_storage<T>::find(entity_id id) const noexcept {
|
||||||
|
const auto iter = components_.find(id);
|
||||||
|
return iter != components_.end()
|
||||||
|
? &iter->second
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// exceptions
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ecs_hpp
|
||||||
|
{
|
||||||
|
class basic_exception : public std::logic_error {
|
||||||
|
public:
|
||||||
|
basic_exception(const char* msg)
|
||||||
|
: std::logic_error(msg) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// entity
|
// entity
|
||||||
@@ -151,6 +186,18 @@ namespace ecs_hpp
|
|||||||
bool exists_component() const noexcept;
|
bool exists_component() const noexcept;
|
||||||
|
|
||||||
std::size_t remove_all_components() noexcept;
|
std::size_t remove_all_components() noexcept;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T& get_component();
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T& get_component() const;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T* find_component() noexcept;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T* find_component() const noexcept;
|
||||||
private:
|
private:
|
||||||
world& owner_;
|
world& owner_;
|
||||||
entity_id id_{0u};
|
entity_id id_{0u};
|
||||||
@@ -199,9 +246,24 @@ namespace ecs_hpp
|
|||||||
bool exists_component(const entity& ent) const noexcept;
|
bool exists_component(const entity& ent) const noexcept;
|
||||||
|
|
||||||
std::size_t remove_all_components(const entity& ent) const noexcept;
|
std::size_t remove_all_components(const entity& ent) const noexcept;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T& get_component(const entity& ent);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T& get_component(const entity& ent) const;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T* find_component(const entity& ent) noexcept;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T* find_component(const entity& ent) const noexcept;
|
||||||
private:
|
private:
|
||||||
template < typename T >
|
template < typename T >
|
||||||
detail::component_storage<T>* find_storage_() const;
|
detail::component_storage<T>* find_storage_() noexcept;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const detail::component_storage<T>* find_storage_() const noexcept;
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
detail::component_storage<T>& get_or_create_storage_();
|
detail::component_storage<T>& get_or_create_storage_();
|
||||||
@@ -271,6 +333,26 @@ namespace ecs_hpp
|
|||||||
return owner_.remove_all_components(*this);
|
return owner_.remove_all_components(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T& entity::get_component() {
|
||||||
|
return owner_.get_component<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T& entity::get_component() const {
|
||||||
|
return owner_.get_component<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T* entity::find_component() noexcept {
|
||||||
|
return owner_.find_component<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T* entity::find_component() const noexcept {
|
||||||
|
return owner_.find_component<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator==(const entity& l, const entity& r) noexcept {
|
inline bool operator==(const entity& l, const entity& r) noexcept {
|
||||||
return &l.owner() == &r.owner()
|
return &l.owner() == &r.owner()
|
||||||
&& l.id() == r.id();
|
&& l.id() == r.id();
|
||||||
@@ -353,7 +435,41 @@ namespace ecs_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
detail::component_storage<T>* world::find_storage_() const {
|
T& world::get_component(const entity& ent) {
|
||||||
|
T* component = find_component<T>(ent);
|
||||||
|
if ( component ) {
|
||||||
|
return *component;
|
||||||
|
}
|
||||||
|
throw basic_exception("component not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T& world::get_component(const entity& ent) const {
|
||||||
|
const T* component = find_component<T>(ent);
|
||||||
|
if ( component ) {
|
||||||
|
return *component;
|
||||||
|
}
|
||||||
|
throw basic_exception("component not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
T* world::find_component(const entity& ent) noexcept {
|
||||||
|
detail::component_storage<T>* storage = find_storage_<T>();
|
||||||
|
return storage
|
||||||
|
? storage->find(ent.id())
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const T* world::find_component(const entity& ent) const noexcept {
|
||||||
|
const detail::component_storage<T>* storage = find_storage_<T>();
|
||||||
|
return storage
|
||||||
|
? storage->find(ent.id())
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
detail::component_storage<T>* world::find_storage_() noexcept {
|
||||||
const auto family = detail::type_family<T>::id();
|
const auto family = detail::type_family<T>::id();
|
||||||
const auto iter = storages_.find(family);
|
const auto iter = storages_.find(family);
|
||||||
if ( iter != storages_.end() ) {
|
if ( iter != storages_.end() ) {
|
||||||
@@ -362,6 +478,16 @@ namespace ecs_hpp
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const detail::component_storage<T>* world::find_storage_() const noexcept {
|
||||||
|
const auto family = detail::type_family<T>::id();
|
||||||
|
const auto iter = storages_.find(family);
|
||||||
|
if ( iter != storages_.end() ) {
|
||||||
|
return static_cast<const detail::component_storage<T>*>(iter->second.get());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
detail::component_storage<T>& world::get_or_create_storage_() {
|
detail::component_storage<T>& world::get_or_create_storage_() {
|
||||||
detail::component_storage<T>* storage = find_storage_<T>();
|
detail::component_storage<T>* storage = find_storage_<T>();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ TEST_CASE("world") {
|
|||||||
REQUIRE_FALSE(w.destroy_entity(e2));
|
REQUIRE_FALSE(w.destroy_entity(e2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SECTION("components") {
|
SECTION("component_assigning") {
|
||||||
{
|
{
|
||||||
ecs::world w;
|
ecs::world w;
|
||||||
ecs::entity e1 = w.create_entity();
|
ecs::entity e1 = w.create_entity();
|
||||||
@@ -147,4 +147,51 @@ TEST_CASE("world") {
|
|||||||
REQUIRE_FALSE(w.exists_component<position_c>(e1));
|
REQUIRE_FALSE(w.exists_component<position_c>(e1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SECTION("component_accessing") {
|
||||||
|
{
|
||||||
|
ecs::world w;
|
||||||
|
|
||||||
|
auto e1 = w.create_entity();
|
||||||
|
auto e2 = w.create_entity();
|
||||||
|
|
||||||
|
REQUIRE_FALSE(e1.find_component<position_c>());
|
||||||
|
REQUIRE_FALSE(e2.find_component<velocity_c>());
|
||||||
|
|
||||||
|
e1.assign_component<position_c>(1, 2);
|
||||||
|
e2.assign_component<velocity_c>(3, 4);
|
||||||
|
|
||||||
|
REQUIRE(e1.get_component<position_c>().x == 1);
|
||||||
|
REQUIRE(e1.get_component<position_c>().y == 2);
|
||||||
|
|
||||||
|
REQUIRE(e2.get_component<velocity_c>().dx == 3);
|
||||||
|
REQUIRE(e2.get_component<velocity_c>().dy == 4);
|
||||||
|
|
||||||
|
REQUIRE_THROWS_AS(e1.get_component<velocity_c>(), ecs::basic_exception);
|
||||||
|
REQUIRE_THROWS_AS(e2.get_component<position_c>(), ecs::basic_exception);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ecs::world w;
|
||||||
|
|
||||||
|
const auto e1 = w.create_entity();
|
||||||
|
const auto e2 = w.create_entity();
|
||||||
|
|
||||||
|
REQUIRE_FALSE(e1.find_component<position_c>());
|
||||||
|
REQUIRE_FALSE(e2.find_component<velocity_c>());
|
||||||
|
|
||||||
|
w.assign_component<position_c>(e1, 1, 2);
|
||||||
|
w.assign_component<velocity_c>(e2, 3, 4);
|
||||||
|
|
||||||
|
{
|
||||||
|
const ecs::world& ww = w;
|
||||||
|
REQUIRE(ww.get_component<position_c>(e1).x == 1);
|
||||||
|
REQUIRE(ww.get_component<position_c>(e1).y == 2);
|
||||||
|
|
||||||
|
REQUIRE(ww.get_component<velocity_c>(e2).dx == 3);
|
||||||
|
REQUIRE(ww.get_component<velocity_c>(e2).dy == 4);
|
||||||
|
|
||||||
|
REQUIRE_THROWS_AS(ww.get_component<velocity_c>(e1), ecs::basic_exception);
|
||||||
|
REQUIRE_THROWS_AS(ww.get_component<position_c>(e2), ecs::basic_exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user