Home (original) (raw)
This first page is a quick reference for when you're looking to jog your memory. See table of contents to the right for a more detailed look.
Members
- create
- query
- events
- extras
create
#include <entt/entity/registry.hpp>
Create a new entity.
entt::entity entity = registry.create();
- Entities are of type
std::uint32_t
per default, they don't store any data. Instead, they associate data; see assign.
Examples
// Typical usage auto entity = registry.create();
// Serialise entities via to_integer auto entity = registry.create(); auto serialised = entt::to_integer(entity); // default is std::uint32_t
// Create in bulk.. std::vectorentt::entity entities(10); registry.create(entities.begin(), entities.end());
// ..with pre-assigned component std::vectorentt::entity entities(10); registry.create<Position, Orientation>(entities.begin(), entities.end());
destroy
Delete an entity, and all of its components.
registry.destroy(entity);
Examples
auto entity = registry.create(); registry.assign(entity); registry.destroy(entity); // entity and the assigned Position component was destroyed
assign
#include <entt/entity/registry.hpp>
Create a new component.
registry.assign(entity);
- Components are initialised on assignment
- Initialiser arguments are optional, but recommended
- Only one component type may exist per entity
- Calling
assign
with an already existing type throws an exception (in Debug) - Use
replace
to replace a component - Or
remove
followed byreplace
to re-trigger theon_construct
handler replace
triggers theon_replace
handler, noton_construct
(despite also being constructed)
Examples
struct Position { float x, y, z; }; auto entity = registry.create(); registry.assign(entity, 1.0f, 2.0f, 4.0f);
The first argument is the entitiy with which to associate this new component, the remaining arguments are passed to the constructor of the component. It is the equivalent of:
Position position { 1.0f, 2.0f, 4.0f }; registy.assign(entity, position);
Passing no arguments default constructs the component.
registry.assign(entity); // Default constructed
remove
The opposite of assign
, remove a single component from an entity.
registry.remove(entity);
Examples
auto entity = registry.create(); registry.assign(entity); registry.remove(entity);
replace
Replace an existing component.
Trying to replace a component not already assigned is undefined
registry.replace(entity, 1.0f, 5.0f);
Examples
auto entity = registry.create(); registry.assign(entity, 5.0f, 2.0f); registry.replace(entity) // default constructed
assign_or_replace
Just assign, no matter what.
registry.assign_or_replace(entity);
Examples
If you're assigning in a loop, you may consider doing..
// somewhere.. registry.assign(entity);
// ..elsewhere while (true) { registry.replace(entity); // other things.. }
However is Position
is removed for whatever reason during other things..
you run into trouble. And whilst you could..
while (true) { if (!registry.has(entity)) { registry.assign(entity); } else { registry.replace(entity); } // other things.. }
A more readable option might be..
while (true) { registry.assign_or_replace(entity); // other things.. }
reset
Remove all components of any or all types.
registry.reset(); // all Position components registry.reset(); // all components (and entities, because what good are they now?)
Examples
Useful for managing selection.
registry.reset();
if (some_condition) { registry.assign(entity); }
Or whether something is hovered.
void mouseMoveEvent(const MouseEvent& event) { registry.reset();
registry.view<Position, Shape>().each([&](auto entity, const auto& pos, const auto& shape) { if (contains(pos, shape, event.position())) { registry.assign(entity); } }); }
get
Components can be explicitly queried from an entity.
auto pos = registry.get(entity);
Examples
auto entity = registry.create(); registry.assign(entity); auto pos = registry.get(entity);
You typically won't get
components, instead you should use view to iterate on components in bulk.
void on_position_created(auto entity) { auto ori = registry.get(entity); }
view
Iterate over a single or combination of components.
for (auto entity : registry.view()) { // ... }
This is the most common method with which to interact with entities and components.
Examples
Iterate over all entities with one specific type of component assigned
auto entity = registry.create(); registry.assign(entity);
for (auto entity : registry.view()) { auto& pos = registry.get(entity); pos.x += 1.0f; }
Iterate over all entites that have a combination of components.
for (auto entity : registry.view<Name, Position, Color>()) { const auto& name = registry.get(entity); const auto& col = registry.get(entity); auto& pos = registry.get(entity);
printf("Adding the red color to the x position of %s", name); pos.x += col.r(); }
For convenient, you can also return two or more components from a single .get<>
.
for (auto entity : registry.view<Name, Position, Color>()) { const auto& [name, col] = registry.get<Name, Color>(entity); auto& pos = registry.get(entity);
printf("Adding the red color to the x position of %s", name); pos.x += col.r(); }
each
Combine view
and get
into a single query with each
.
registry.view().each([](auto entity, auto& pos) { pos.x += 1.0f; });
Examples
If you don't need to access the entity
, then don't include it.
registry.view<Name, Position, Color>().each([](const auto& name, auto& pos, const auto& col) { printf("Adding the red color to the x position of %s", name); pos.x += col.r(); });
less
A view returns entities that carry all of the specified components. Like a filter. Sometimes it may make sense to use components strictly for filtering.
struct IsAlive {};
// ...
registry.view<IsAlive, Position>().each([](const auto& isalive, auto& pos) { printf("An entity at (%d, %d) is alive!\n", pos.x, pos.y); });
As an empty struct doesn't provide any information and serve no purpose inside of your loop, they would not be missed if not included. And that's what less
is for.
registry.view<IsAlive, Position>().less([](auto& pos) { printf("An entity at (%d, %d) is alive!\n", pos.x, pos.y); });
See how much more readable that is?
has
Check whether an entity has a component with registry::has
if (entt::has(entity)) { // do work.. }
Example
Iterating over components is both branchless and guaranteed to never hand you a nullptr
. This is where view is more pleasant to work with than get
, but in the few cases where you need get
, how can you be sure the component you're asking for exists?
auto id = registry.try_get(entity); if (id) { id.name = "Alan"; }
// Equivalent to if (registry.has(entity)) { auto id = registry.get(entity); id.name = "Alan"; }
on_construct
Call a function or method when a component has been constructed.
entt::on_construct(&onPositionConstructed);
Example
In object-oriented programming, types have a constructor. Constructors come in handy when there is more to initialisation than just de-nullifying initial values. With on_construct
you can achieve similar benefit, but in an ECS way.
struct Position { float x, y, z; };
void on_position_created(entt::entity ent, entt:registry& reg, Position& pos) { pos.x = 0.5; pos.y = pos.x / 2.0; pos.z = pos.x + pos.z; }
// Attach event handler registry.on_construct().connect<&on_position_created>();
auto player = registry.create(); registry.assign(player); // <-- called here (after creation)
Alternatives
// Equally valid argument signatures; less arguments is faster void on_position_created_1(entt::entity ent, entt:registry& reg, Position& pos) {} void on_position_created_2(entt::entity ent, entt:registry& reg) {} void on_position_created_3(entt::entity ent) {}
observer
#include <entt/entity/observer.hpp>
Where on_construct
executes a callback on the exact moment of a component being constructed, an entt::observer
can defer a callback until explicitly called.
entt::observer newPositions { registry, entt::collector.group() };
auto entity = registry.create(); registry.assign(entity);
for (const auto e : newPositions) { assert(e == entity); }
Member | Description |
---|---|
entt::collector | A.k.a. "rule", when to consider an event related to a given observer. Name inherited from the Entitas project |
entt::collector.group |