Skip to content

Instantly share code, notes, and snippets.

@ArnCarveris
Last active February 21, 2018 19:26
Show Gist options
  • Save ArnCarveris/302da50d2a7d97d42c4b3c4c5a428108 to your computer and use it in GitHub Desktop.
Save ArnCarveris/302da50d2a7d97d42c4b3c4c5a428108 to your computer and use it in GitHub Desktop.
EnTT grouping

#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 &registry) {
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 &registry) {
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