#### Querying entities and their components
-To query all entities with a set of components assigned, use ``entityx::EntityManager::entities_with_components()``. This method will return only those entities that have *all* of the specified components associated with them, assigning each component pointer to the corresponding component instance:
+To query all entities with a set of components assigned you can use two
+methods. Both methods will return only those entities that have *all* of the
+specified components associated with them.
+
+`entityx::EntityManager::each(f) provides functional-style iteration over
+`entity components. The callback for `each()` can optionally accept an Entity as
+`its first argument.
+
+```c++
+entities.each<Position, Direction>([](Entity entity, Position &position, Direction &direction) {
+ // Do things with entity, position and direction.
+};)
+```
+
+
+For iterator-style traversal of components, use
+``entityx::EntityManager::entities_with_components()``:
```c++
ComponentHandle<Position> position;
```c++
struct MovementSystem : public System<MovementSystem> {
void update(entityx::EntityManager &es, entityx::EventManager &events, TimeDelta dt) override {
- ComponentHandle<Position> position;
- ComponentHandle<Direction> direction;
- for (Entity entity : es.entities_with_components(position, direction)) {
- position->x += direction->x * dt;
- position->y += direction->y * dt;
- }
+ es.each<Position, Direction>([dt](Position &position, Direction &direction) {
+ position.x += direction.x * dt;
+ position.y += direction.y * dt;
+ });
};
};
```
void next_entity(Entity &entity) {}
};
-
Iterator begin() { return Iterator(manager_, mask_, 0); }
Iterator end() { return Iterator(manager_, mask_, uint32_t(manager_->capacity())); }
const Iterator begin() const { return Iterator(manager_, mask_, 0); }
ComponentMask mask_;
};
- typedef BaseView<false> View;
+ template <bool All, typename ... Components>
+ class TypedView: public BaseView<All> {
+ public:
+ template <typename T> struct identity { typedef T type; };
+
+ void each(typename identity<std::function<void(Components&...)>>::type f) {
+ for (auto it : *this)
+ f(*(it.template component<Components>().get())...);
+ }
+
+ void each(typename identity<std::function<void(Entity entity, Components&...)>>::type f) {
+ for (auto it : *this)
+ f(it, *(it.template component<Components>().get())...);
+ }
+
+ private:
+ friend class EntityManager;
+
+ explicit TypedView(EntityManager *manager) : BaseView<All>(manager) {}
+ TypedView(EntityManager *manager, ComponentMask mask) : BaseView<All>(manager, mask) {}
+ };
+
+ template <typename ... Components> using View = TypedView<false, Components...>;
typedef BaseView<true> DebugView;
template <typename ... Components>
unpack_<0, Components...>(entity);
}
+
private:
template <int N, typename C>
void unpack_(entityx::Entity &entity) const {
* @endcode
*/
template <typename ... Components>
- View entities_with_components() {
+ View<Components...> entities_with_components() {
auto mask = component_mask<Components ...>();
- return View(this, mask);
+ return View<Components...>(this, mask);
+ }
+
+ template <typename T> struct identity { typedef T type; };
+
+ template <typename ... Components>
+ void each(typename identity<std::function<void(Components&...)>>::type f) {
+ return entities_with_components<Components...>().each(f);
+ }
+
+ template <typename ... Components>
+ void each(typename identity<std::function<void(Entity entity, Components&...)>>::type f) {
+ return entities_with_components<Components...>().each(f);
}
/**
REQUIRE(b.component<const Position>()->x == 1);
REQUIRE(b.component<const Position>()->y == 2);
}
+
+TEST_CASE_METHOD(EntityManagerFixture, "TestEntityManagerEach") {
+ Entity a = em.create();
+ a.assign<Position>(1, 2);
+ int count = 0;
+ em.each<Position>([&count](Position &position) {
+ count++;
+ REQUIRE(position.x == 1);
+ REQUIRE(position.y == 2);
+ });
+ REQUIRE(count == 1);
+}
+
+TEST_CASE_METHOD(EntityManagerFixture, "TestViewEach") {
+ Entity a = em.create();
+ a.assign<Position>(1, 2);
+ int count = 0;
+ em.entities_with_components<Position>().each([&count](Position &position) {
+ count++;
+ REQUIRE(position.x == 1);
+ REQUIRE(position.y == 2);
+ });
+ REQUIRE(count == 1);
+}
+
+TEST_CASE_METHOD(EntityManagerFixture, "TestViewEachWithEntity") {
+ Entity a = em.create();
+ a.assign<Position>(1, 2);
+ int count = 0;
+ em.entities_with_components<Position>().each([&count](Entity entity, Position &position) {
+ count++;
+ REQUIRE(position.x == 1);
+ REQUIRE(position.y == 2);
+ REQUIRE(*entity.component<Position>().get() == position);
+ });
+ REQUIRE(count == 1);
+}
void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override {
int c = 0;
ex::ComponentHandle<Collideable> collideable;
- for (ex::Entity entity : es.entities_with_components<Collideable>()) c++;
+ es.each<Collideable>([&](Collideable&) { ++c; });
for (int i = 0; i < count - c; i++) {
ex::Entity entity = es.create();
// Updates a body's position and rotation.
struct BodySystem : public ex::System<BodySystem> {
void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override {
- ex::ComponentHandle<Body> body;
- for (ex::Entity entity : es.entities_with_components(body)) {
- body->position += body->direction * static_cast<float>(dt);
- body->rotation += body->rotationd * dt;
- }
+ es.each<Body>([dt](Body &body) {
+ body.position += body.direction * static_cast<float>(dt);
+ body.rotation += body.rotationd * dt;
+ });
};
};
explicit BounceSystem(sf::RenderTarget &target) : size(target.getSize()) {}
void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override {
- ex::ComponentHandle<Body> body;
- for (ex::Entity entity : es.entities_with_components(body)) {
- if (body->position.x + body->direction.x < 0 ||
- body->position.x + body->direction.x >= size.x)
- body->direction.x = -body->direction.x;
- if (body->position.y + body->direction.y < 0 ||
- body->position.y + body->direction.y >= size.y)
- body->direction.y = -body->direction.y;
- }
+ es.each<Body>([this](Body &body) {
+ if (body.position.x + body.direction.x < 0 ||
+ body.position.x + body.direction.x >= size.x)
+ body.direction.x = -body.direction.x;
+ if (body.position.y + body.direction.y < 0 ||
+ body.position.y + body.direction.y >= size.y)
+ body.direction.y = -body.direction.y;
+ });
}
private:
}
void collect(ex::EntityManager &entities) {
- ex::ComponentHandle<Body> body;
- ex::ComponentHandle<Collideable> collideable;
- for (ex::Entity entity : entities.entities_with_components(body, collideable)) {
+ entities.each<Body, Collideable>([this](ex::Entity entity, Body &body, Collideable &collideable) {
unsigned int
- left = static_cast<int>(body->position.x - collideable->radius) / PARTITIONS,
- top = static_cast<int>(body->position.y - collideable->radius) / PARTITIONS,
- right = static_cast<int>(body->position.x + collideable->radius) / PARTITIONS,
- bottom = static_cast<int>(body->position.y + collideable->radius) / PARTITIONS;
- Candidate candidate {body->position, collideable->radius, entity};
+ left = static_cast<int>(body.position.x - collideable.radius) / PARTITIONS,
+ top = static_cast<int>(body.position.y - collideable.radius) / PARTITIONS,
+ right = static_cast<int>(body.position.x + collideable.radius) / PARTITIONS,
+ bottom = static_cast<int>(body.position.y + collideable.radius) / PARTITIONS;
+ Candidate candidate {body.position, collideable.radius, entity};
unsigned int slots[4] = {
left + top * size.x,
right + top * size.x,
if (slots[0] != slots[1]) grid[slots[1]].push_back(candidate);
if (slots[1] != slots[2]) grid[slots[2]].push_back(candidate);
if (slots[2] != slots[3]) grid[slots[3]].push_back(candidate);
- }
+ });
}
void collide(ex::EventManager &events) {
class ParticleSystem : public ex::System<ParticleSystem> {
public:
void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override {
- ex::ComponentHandle<Particle> particle;
- for (ex::Entity entity : es.entities_with_components(particle)) {
- particle->alpha -= particle->d * dt;
- if (particle->alpha <= 0) {
+ es.each<Particle>([dt](ex::Entity entity, Particle &particle) {
+ particle.alpha -= particle.d * dt;
+ if (particle.alpha <= 0) {
entity.destroy();
} else {
- particle->colour.a = particle->alpha;
+ particle.colour.a = particle.alpha;
}
- }
+ });
}
};
void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override {
sf::VertexArray vertices(sf::Quads);
- ex::ComponentHandle<Particle> particle;
- ex::ComponentHandle<Body> body;
- for (ex::Entity entity : es.entities_with_components(body, particle)) {
- float r = particle->radius;
- vertices.append(sf::Vertex(body->position + sf::Vector2f(-r, -r), particle->colour));
- vertices.append(sf::Vertex(body->position + sf::Vector2f(r, -r), particle->colour));
- vertices.append(sf::Vertex(body->position + sf::Vector2f(r, r), particle->colour));
- vertices.append(sf::Vertex(body->position + sf::Vector2f(-r, r), particle->colour));
- }
+ es.each<Particle, Body>([&vertices](Particle &particle, Body &body) {
+ const float r = particle.radius;
+ vertices.append(sf::Vertex(body.position + sf::Vector2f(-r, -r), particle.colour));
+ vertices.append(sf::Vertex(body.position + sf::Vector2f(r, -r), particle.colour));
+ vertices.append(sf::Vertex(body.position + sf::Vector2f(r, r), particle.colour));
+ vertices.append(sf::Vertex(body.position + sf::Vector2f(-r, r), particle.colour));
+ });
target.draw(vertices);
}
private:
}
void update(ex::EntityManager &es, ex::EventManager &events, ex::TimeDelta dt) override {
- ex::ComponentHandle<Body> body;
- ex::ComponentHandle<Renderable> renderable;
- for (ex::Entity entity : es.entities_with_components(body, renderable)) {
- renderable->shape->setPosition(body->position);
- renderable->shape->setRotation(body->rotation);
- target.draw(*renderable->shape.get());
- }
+ es.each<Body, Renderable>([this](Body &body, Renderable &renderable) {
+ renderable.shape->setPosition(body.position);
+ renderable.shape->setRotation(body.rotation);
+ target.draw(*renderable.shape.get());
+ });
last_update += dt;
frame_count++;
if (last_update >= 0.5) {