Last active
February 21, 2018 19:26
-
-
Save ArnCarveris/302da50d2a7d97d42c4b3c4c5a428108 to your computer and use it in GitHub Desktop.
EnTT grouping
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| |
#include <entt/entt.hpp> | |
#include <cstdint> | |
#include <deque> | |
namespace entt | |
{ | |
template<typename Entity> using Group = Registry<Entity>; | |
template<typename Entity> class GroupRegistry | |
{ | |
public: | |
using size_type = std::size_t; | |
using group_id = size_type; | |
using group_type = Group<Entity>; | |
public: | |
GroupRegistry() = default; | |
GroupRegistry(const GroupRegistry &) = delete; | |
GroupRegistry(GroupRegistry &&) = default; | |
GroupRegistry & operator=(const GroupRegistry &) = delete; | |
GroupRegistry & operator=(GroupRegistry &&) = default; | |
public: | |
group_id create() noexcept | |
{ | |
group_id group = 0; | |
if (freed.empty()) | |
{ | |
group = groups.size(); | |
groups.emplace_back(group_type()); | |
} | |
else | |
{ | |
group = freed.front(); | |
freed.pop_front(); | |
} | |
return group; | |
} | |
bool valid(group_id group) const noexcept | |
{ | |
return group < groups.size(); | |
} | |
bool has(group_id group) const noexcept | |
{ | |
assert(valid(group)); | |
for (auto& idx : freed) | |
{ | |
if (idx == group) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
group_type& get(group_id group) noexcept | |
{ | |
return groups[group]; | |
} | |
bool remove(group_id group) | |
{ | |
if (has(group)) | |
{ | |
get(group).reset(); | |
freed.emplace_back(group); | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
void reset() | |
{ | |
groups.clear(); | |
freed.clear(); | |
} | |
size_type size() const noexcept | |
{ | |
return groups.size() - freed.size(); | |
} | |
size_type capacity() const noexcept | |
{ | |
return groups.size(); | |
} | |
bool empty() const noexcept | |
{ | |
return groups.size() == freed.size(); | |
} | |
private: | |
std::deque<group_type> groups; | |
std::deque<group_id> freed; | |
}; | |
using DefaultGroup = Group<std::uint32_t>; | |
using DefaultGroupRegistry = GroupRegistry<std::uint32_t>; | |
} | |
struct Position { | |
float x; | |
float y; | |
}; | |
struct Velocity { | |
float dx; | |
float dy; | |
}; | |
struct GroupEntry | |
{ | |
entt::DefaultGroupRegistry::group_id id; | |
}; | |
struct LinkInGroup | |
{ | |
entt::DefaultGroupRegistry::group_id group; | |
entt::DefaultRegistry::entity_type entity; | |
}; | |
void visit( | |
entt::DefaultGroupRegistry &groups, | |
entt::DefaultGroupRegistry::group_id id, | |
const std::function<bool(entt::DefaultGroup&)>& fn) | |
{ | |
auto& registry = groups.get(id); | |
if (fn && !fn(registry)) | |
{ | |
return; | |
} | |
auto view = registry.view<GroupEntry>(); | |
for (auto entity : view) | |
{ | |
auto& group = view.get(entity); | |
visit(groups, group.id, fn); | |
} | |
} | |
void update(entt::DefaultRegistry ®istry) { | |
auto view = registry.view<Position, Velocity>(); | |
for (auto entity : view) { | |
// gets only the components that are going to be used ... | |
auto &velocity = view.get<Velocity>(entity); | |
velocity.dx = 0.; | |
velocity.dy = 0.; | |
// ... | |
} | |
} | |
void update(std::uint64_t dt, entt::DefaultRegistry ®istry) { | |
registry.view<Position, Velocity>().each([dt](auto entity, auto &position, auto &velocity) { | |
// gets all the components of the view at once ... | |
position.x += velocity.dx * dt; | |
position.y += velocity.dy * dt; | |
// ... | |
}); | |
} | |
int main() { | |
entt::DefaultGroupRegistry rex; | |
rex.remove(rex.create()); | |
auto root = rex.create(); | |
auto child = rex.create(); | |
{ | |
auto& reg = rex.get(root); | |
for (auto i = 0; i < 3; ++i) | |
{ | |
auto entity = reg.create(Position{ i * 2.f, i * 1.f }); | |
if (i == 0) { reg.assign<GroupEntry>(entity, child); } | |
} | |
} | |
auto leaf = rex.create(); | |
{ | |
auto& reg = rex.get(child); | |
for (auto i = 0; i < 5; ++i) | |
{ | |
auto entity = reg.create(Position{ i * 1.f, i * 3.f }); | |
if (i == 0) { reg.assign<GroupEntry>(entity, leaf); } | |
} | |
} | |
{ | |
auto& reg = rex.get(leaf); | |
for (auto i = 0; i < 10; ++i) | |
{ | |
auto entity = reg.create(Position{ i * 4.f, i * 4.f }); | |
if (i % 2 == 0) { reg.assign<Velocity>(entity, i * .1f, i * .1f); } | |
} | |
} | |
visit(rex, root, [](entt::DefaultGroup& reg) { | |
update(reg); | |
return true; | |
}); | |
visit(rex, root, [](entt::DefaultGroup& reg) { | |
update(10, reg); | |
return true; | |
}); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment