add entity cloning

This commit is contained in:
2019-04-10 02:08:55 +07:00
parent 007f1b228c
commit 24bfcaf7eb
2 changed files with 86 additions and 10 deletions

53
ecs.hpp
View File

@@ -322,7 +322,7 @@ namespace ecs_hpp
}
bool unordered_erase(const T& v) noexcept(
noexcept(indexer_(std::declval<T>())) &&
noexcept(std::declval<Indexer>()(std::declval<T>())) &&
std::is_nothrow_move_assignable<T>::value)
{
if ( !has(v) ) {
@@ -343,7 +343,7 @@ namespace ecs_hpp
}
bool has(const T& v) const noexcept(
noexcept(indexer_(std::declval<T>())))
noexcept(std::declval<Indexer>()(std::declval<T>())))
{
const std::size_t vi = indexer_(v);
return vi < sparse_.size()
@@ -352,7 +352,7 @@ namespace ecs_hpp
}
const_iterator find(const T& v) const noexcept(
noexcept(indexer_(std::declval<T>())))
noexcept(std::declval<Indexer>()(std::declval<T>())))
{
return has(v)
? begin() + sparse_[indexer_(v)]
@@ -368,7 +368,7 @@ namespace ecs_hpp
}
std::pair<std::size_t,bool> find_dense_index(const T& v) const noexcept(
noexcept(indexer_(std::declval<T>())))
noexcept(std::declval<Indexer>()(std::declval<T>())))
{
return has(v)
? std::make_pair(sparse_[indexer_(v)], true)
@@ -486,7 +486,7 @@ namespace ecs_hpp
}
bool unordered_erase(const K& k) noexcept(
noexcept(keys_.find_dense_index(k)) &&
noexcept(std::declval<sparse_set<K, Indexer>>().find_dense_index(k)) &&
std::is_nothrow_move_assignable<T>::value)
{
static_assert(
@@ -510,7 +510,7 @@ namespace ecs_hpp
}
bool has(const K& k) const noexcept(
noexcept(keys_.has(k)))
noexcept(std::declval<sparse_set<K, Indexer>>().has(k)))
{
return keys_.has(k);
}
@@ -524,7 +524,7 @@ namespace ecs_hpp
}
T* find(const K& k) noexcept(
noexcept(keys_.find_dense_index(k)))
noexcept(std::declval<sparse_set<K, Indexer>>().find_dense_index(k)))
{
const auto value_index_p = keys_.find_dense_index(k);
return value_index_p.second
@@ -533,7 +533,7 @@ namespace ecs_hpp
}
const T* find(const K& k) const noexcept(
noexcept(keys_.find_dense_index(k)))
noexcept(std::declval<sparse_set<K, Indexer>>().find_dense_index(k)))
{
const auto value_index_p = keys_.find_dense_index(k);
return value_index_p.second
@@ -588,6 +588,7 @@ namespace ecs_hpp
virtual ~component_storage_base() = default;
virtual bool remove(entity_id id) noexcept = 0;
virtual bool has(entity_id id) const noexcept = 0;
virtual void clone(entity_id from, entity_id to) = 0;
};
template < typename T >
@@ -605,6 +606,7 @@ namespace ecs_hpp
std::size_t count() const noexcept;
bool has(entity_id id) const noexcept override;
void clone(entity_id from, entity_id to) override;
template < typename F >
void for_each_component(F&& f);
@@ -655,10 +657,18 @@ namespace ecs_hpp
return components_.has(id);
}
template < typename T >
void component_storage<T>::clone(entity_id from, entity_id to) {
const T* c = components_.find(from);
if ( c ) {
components_.insert_or_assign(to, *c);
}
}
template < typename T >
template < typename F >
void component_storage<T>::for_each_component(F&& f) {
for ( const auto id : components_ ) {
for ( const entity_id id : components_ ) {
f(id, components_.get(id));
}
}
@@ -666,7 +676,7 @@ namespace ecs_hpp
template < typename T >
template < typename F >
void component_storage<T>::for_each_component(F&& f) const {
for ( const auto id : components_ ) {
for ( const entity_id id : components_ ) {
f(id, components_.get(id));
}
}
@@ -699,6 +709,7 @@ namespace ecs_hpp
bool destroy();
bool alive() const noexcept;
entity clone() const;
template < typename T, typename... Args >
bool assign_component(Args&&... args);
@@ -1032,6 +1043,7 @@ namespace ecs_hpp
const_component<T> wrap_component(const const_uentity& ent) const noexcept;
entity create_entity();
entity create_entity(const const_uentity& prototype);
bool destroy_entity(const uentity& ent);
bool alive_entity(const const_uentity& ent) const noexcept;
@@ -1244,6 +1256,10 @@ namespace ecs_hpp
return detail::as_const(*owner_).alive_entity(id_);
}
inline entity entity::clone() const {
return (*owner_).create_entity(id_);
}
template < typename T, typename... Args >
bool entity::assign_component(Args&&... args) {
return (*owner_).assign_component<T>(
@@ -1691,6 +1707,23 @@ namespace ecs_hpp
throw std::logic_error("ecs_hpp::registry (entity index overlow)");
}
inline entity registry::create_entity(const const_uentity& prototype) {
assert(prototype.check_owner(this));
entity ent = create_entity();
if ( !alive_entity(prototype) ) {
return ent;
}
try {
for ( const auto family_id : storages_ ) {
storages_.get(family_id)->clone(prototype, ent.id());
}
} catch (...) {
destroy_entity(ent);
throw;
}
return ent;
}
inline bool registry::destroy_entity(const uentity& ent) {
assert(ent.check_owner(this));
remove_all_components(ent);

View File

@@ -732,6 +732,49 @@ TEST_CASE("registry") {
REQUIRE(e1.get_component<velocity_c>().y == 40);
}
}
SECTION("cloning") {
{
ecs::registry w;
auto e1 = w.create_entity();
ecs::entity_filler(e1)
.component<position_c>(1, 2)
.component<velocity_c>(3, 4);
auto e2 = w.create_entity(e1);
REQUIRE(w.component_count<position_c>() == 2);
REQUIRE(w.component_count<velocity_c>() == 2);
REQUIRE(e2.exists_component<position_c>());
REQUIRE(e2.exists_component<velocity_c>());
REQUIRE(e2.get_component<position_c>() == position_c(1, 2));
REQUIRE(e2.get_component<velocity_c>() == velocity_c(3, 4));
e2.remove_component<velocity_c>();
auto e3 = e2.clone();
REQUIRE(w.component_count<position_c>() == 3);
REQUIRE(w.component_count<velocity_c>() == 1);
REQUIRE(e3.exists_component<position_c>());
REQUIRE_FALSE(e3.exists_component<velocity_c>());
REQUIRE(e3.get_component<position_c>() == position_c(1, 2));
}
{
ecs::registry w;
auto e1 = w.create_entity();
ecs::entity_filler(e1)
.component<position_c>(1, 2)
.component<velocity_c>(3, 4);
e1.destroy();
auto e2 = e1.clone();
REQUIRE_FALSE(e2.exists_component<position_c>());
REQUIRE_FALSE(e2.exists_component<velocity_c>());
REQUIRE(w.component_count<position_c>() == 0);
REQUIRE(w.component_count<velocity_c>() == 0);
}
}
SECTION("for_each_entity") {
{
ecs::registry w;