aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md14
-rw-r--r--entityx/Components.h2
-rw-r--r--entityx/Components_test.cc2
-rw-r--r--entityx/Entity.h150
-rw-r--r--entityx/Entity_test.cc67
-rw-r--r--entityx/System_test.cc4
6 files changed, 147 insertions, 92 deletions
diff --git a/README.md b/README.md
index 0ca2918..611dc98 100644
--- a/README.md
+++ b/README.md
@@ -50,18 +50,18 @@ struct Direction : Component<Direction> {
#### Assigning components to entities
-To associate a component with a previously created entity call ``EntityManager::assign<C>()`` with the component type, the entity, and any component constructor arguments:
+To associate a component with a previously created entity call ``Entity::assign<C>()`` with the component type, and any component constructor arguments:
```c++
// Assign a Position with x=1.0f and y=2.0f to "entity"
-entities.assign<Position>(entity, 1.0f, 2.0f);
+entity.assign<Position>(1.0f, 2.0f);
```
You can also assign existing instances of components:
```c++
boost::shared_ptr<Position> position = boost::make_shared<Position>(1.0f, 2.0f);
-entities.assign(entity, position);
+entity.assign(position);
```
#### Querying entities and their components
@@ -76,10 +76,10 @@ for (auto entity : entities.entities_with_components(position, direction)) {
}
```
-To retrieve a component associated with an entity use ``EntityManager::component()``:
+To retrieve a component associated with an entity use ``Entity::component<C>()``:
```c++
-boost::shared_ptr<Position> position = entities.component<Position>();
+boost::shared_ptr<Position> position = entity.component<Position>();
if (position) {
// Do stuff with position
}
@@ -186,8 +186,8 @@ class GameManager : public Manager {
// Create some entities in random locations heading in random directions
for (int i = 0; i < 100; ++i) {
Entity entity = entity_manager.create();
- entity_manager.assign<Position>(entity, rand() % 100, rand() % 100);
- entity_manager.assign<Direction>(entity, (rand() % 10) - 5, (rand() % 10) - 5);
+ entity.assign<Position>(rand() % 100, rand() % 100);
+ entity.assign<Direction>((rand() % 10) - 5, (rand() % 10) - 5);
}
}
diff --git a/entityx/Components.h b/entityx/Components.h
index cbc74d9..c963302 100644
--- a/entityx/Components.h
+++ b/entityx/Components.h
@@ -23,7 +23,7 @@ class TagsComponent : public Component<TagsComponent> {
struct TagsPredicate {
TagsPredicate(const std::string &tag) : tag(tag) {}
- bool operator () (EntityManager &manager, Entity id) {
+ bool operator () (EntityManager &manager, Entity::Id id) {
auto tags = manager.component<TagsComponent>(id);
return tags != nullptr && tags->tags.find(tag) != tags->tags.end();
}
diff --git a/entityx/Components_test.cc b/entityx/Components_test.cc
index bb9ae5d..8fe05ec 100644
--- a/entityx/Components_test.cc
+++ b/entityx/Components_test.cc
@@ -40,7 +40,7 @@ TEST(TagsComponentTest, TestVariadicConstruction) {
TEST(TagsComponentTest, TestEntitiesWithTag) {
EventManager ev;
EntityManager en(ev);
- Entity a = en.create();
+ Entity::Id a = en.create();
en.assign<Position>(a);
for (int i = 0; i < 99; ++i) {
auto e = en.create();
diff --git a/entityx/Entity.h b/entityx/Entity.h
index b90abe7..e763214 100644
--- a/entityx/Entity.h
+++ b/entityx/Entity.h
@@ -27,13 +27,42 @@
namespace entityx {
+
+class EntityManager;
+
+
/**
- * Entity handle.
+ * A convenience handle around an Entity::Id.
*/
-typedef uint64_t Entity;
+class Entity {
+ public:
+ typedef uint64_t Id;
+ Id id() const { return id_; }
-class EntityManager;
+ operator Id () { return id_; }
+
+ template <typename C>
+ boost::shared_ptr<C> assign(boost::shared_ptr<C> component);
+ template <typename C, typename ... Args>
+ boost::shared_ptr<C> assign(Args && ... args);
+
+ template <typename C>
+ boost::shared_ptr<C> component();
+
+ template <typename A>
+ void unpack(boost::shared_ptr<A> &a);
+ template <typename A, typename B, typename ... Args>
+ void unpack(boost::shared_ptr<A> &a, boost::shared_ptr<B> &b, Args && ... args);
+
+ private:
+ friend class EntityManager;
+
+ Entity(EntityManager &entities, Entity::Id id) : entities_(entities), id_(id) {}
+
+ EntityManager &entities_;
+ Entity::Id id_;
+};
/**
@@ -54,7 +83,7 @@ struct BaseComponent {
* Component implementations should inherit from this.
*
* Components MUST provide a no-argument constructor.
- * Components SHOULD provide convenience constructors for initializing on assignment to an Entity.
+ * Components SHOULD provide convenience constructors for initializing on assignment to an Entity::Id.
*
* This is a struct to imply that components should be data-only.
*
@@ -85,20 +114,20 @@ struct Component : public BaseComponent {
* Emitted when an entity is added to the system.
*/
struct EntityCreatedEvent : public Event<EntityCreatedEvent> {
- EntityCreatedEvent(EntityManager &manager, Entity entity) :
+ EntityCreatedEvent(EntityManager &manager, Entity::Id entity) :
manager(manager), entity(entity) {}
EntityManager &manager;
- Entity entity;
+ Entity::Id entity;
};
struct EntityDestroyedEvent : public Event<EntityDestroyedEvent> {
- EntityDestroyedEvent(EntityManager &manager, Entity entity) :
+ EntityDestroyedEvent(EntityManager &manager, Entity::Id entity) :
manager(manager), entity(entity) {}
EntityManager &manager;
- Entity entity;
+ Entity::Id entity;
};
@@ -107,27 +136,27 @@ struct EntityDestroyedEvent : public Event<EntityDestroyedEvent> {
*/
template <typename T>
struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
- ComponentAddedEvent(EntityManager &manager, Entity entity, boost::shared_ptr<T> component) :
+ ComponentAddedEvent(EntityManager &manager, Entity::Id entity, boost::shared_ptr<T> component) :
manager(manager), entity(entity), component(component) {}
EntityManager &manager;
- Entity entity;
+ Entity::Id entity;
boost::shared_ptr<T> component;
};
/**
- * Manages Entity creation and component assignment.
+ * Manages Entity::Id creation and component assignment.
*
* eg.
* EntityManager e;
*
* Entity player = e.create();
*
- * e.assign<Movable>(player);
- * e.assign<Physical>(player);
- * e.assign<Scriptable>(player);
- * shared_ptr<Controllable> controllable = e.assign<Controllable>(player);
+ * player.assign<Movable>();
+ * player.assign<Physical>();
+ * player.assign<Scriptable>();
+ * shared_ptr<Controllable> controllable = player.assign<Controllable>();
*/
class EntityManager : boost::noncopyable {
private:
@@ -138,14 +167,14 @@ class EntityManager : boost::noncopyable {
class View {
public:
- typedef boost::function<bool (EntityManager &, Entity)> Predicate;
+ typedef boost::function<bool (EntityManager &, Entity::Id)> Predicate;
/// A predicate that excludes entities that don't match the given component mask.
class ComponentMaskPredicate {
public:
ComponentMaskPredicate(const std::vector<uint64_t> &entity_bits, uint64_t mask) : entity_bits_(entity_bits), mask_(mask) {}
- bool operator () (EntityManager &, Entity entity) {
+ bool operator () (EntityManager &, Entity::Id entity) {
return (entity_bits_.at(entity) & mask_) == mask_;
}
@@ -155,7 +184,7 @@ class EntityManager : boost::noncopyable {
};
/// An iterator over a view of the entities in an EntityManager.
- class Iterator : public std::iterator<std::input_iterator_tag, Entity> {
+ class Iterator : public std::iterator<std::input_iterator_tag, Entity::Id> {
public:
Iterator &operator ++ () {
++i_;
@@ -164,14 +193,14 @@ class EntityManager : boost::noncopyable {
}
bool operator == (const Iterator& rhs) const { return i_ == rhs.i_; }
bool operator != (const Iterator& rhs) const { return i_ != rhs.i_; }
- Entity & operator * () { return i_; }
- const Entity & operator * () const { return i_; }
+ Entity operator * () { return Entity(manager_, i_); }
+ const Entity operator * () const { return Entity(manager_, i_); }
private:
friend class View;
Iterator(EntityManager &manager, const std::vector<Predicate> &predicates,
- const std::vector<boost::function<void (Entity)>> &unpackers, Entity entity)
+ const std::vector<boost::function<void (Entity::Id)>> &unpackers, Entity::Id entity)
: manager_(manager), predicates_(predicates), unpackers_(unpackers), i_(entity) {
next();
}
@@ -198,8 +227,8 @@ class EntityManager : boost::noncopyable {
EntityManager &manager_;
const std::vector<Predicate> predicates_;
- std::vector<boost::function<void (Entity)>> unpackers_;
- Entity i_;
+ std::vector<boost::function<void (Entity::Id)>> unpackers_;
+ Entity::Id i_;
};
// Create a sub-view with an additional predicate.
@@ -216,7 +245,7 @@ class EntityManager : boost::noncopyable {
View &unpack_to(boost::shared_ptr<A> &a) {
unpackers_.push_back(Unpacker<A>(manager_, a));
// This resulted in a segfault under clang 4.1 on OSX. No idea why.
- /*unpackers_.push_back([&a, this](Entity id) {
+ /*unpackers_.push_back([&a, this](Entity::Id id) {
a = manager_.component<A>(id);
});*/
return *this;
@@ -234,7 +263,7 @@ class EntityManager : boost::noncopyable {
struct Unpacker {
Unpacker(EntityManager &manager, boost::shared_ptr<T> &c) : manager(manager), c(c) {}
- void operator () (Entity id) {
+ void operator () (Entity::Id id) {
c = manager.component<T>(id);
}
@@ -249,7 +278,7 @@ class EntityManager : boost::noncopyable {
EntityManager &manager_;
std::vector<Predicate> predicates_;
- std::vector<boost::function<void (Entity)>> unpackers_;
+ std::vector<boost::function<void (Entity::Id)>> unpackers_;
};
/**
@@ -258,12 +287,12 @@ class EntityManager : boost::noncopyable {
size_t size() const { return entity_component_mask_.size(); }
/**
- * Create a new Entity.
+ * Create a new Entity::Id.
*
* Emits EntityCreatedEvent.
*/
Entity create() {
- Entity id;
+ Entity::Id id;
if (free_list_.empty()) {
id = id_counter_++;
accomodate_entity(id);
@@ -271,16 +300,16 @@ class EntityManager : boost::noncopyable {
id = *free_list_.erase(free_list_.begin());
}
event_manager_.emit<EntityCreatedEvent>(*this, id);
- return id;
+ return Entity(*this, id);
}
/**
- * Destroy an existing Entity and its associated Components.
+ * Destroy an existing Entity::Id and its associated Components.
*
* Emits EntityDestroyedEvent.
*/
- void destroy(Entity entity) {
- CHECK(entity < entity_component_mask_.size()) << "Entity ID outside entity vector range";
+ void destroy(Entity::Id entity) {
+ CHECK(entity < entity_component_mask_.size()) << "Entity::Id ID outside entity vector range";
event_manager_.emit<EntityDestroyedEvent>(*this, entity);
for (auto &components : entity_components_) {
components.at(entity).reset();
@@ -290,9 +319,9 @@ class EntityManager : boost::noncopyable {
}
/**
- * Check if an Entity is registered.
+ * Check if an Entity::Id is registered.
*/
- bool exists(Entity entity) {
+ bool exists(Entity::Id entity) {
if (entity_component_mask_.empty() || entity >= id_counter_) {
return false;
}
@@ -300,12 +329,12 @@ class EntityManager : boost::noncopyable {
}
/**
- * Assigns a previously constructed Component to an Entity.
+ * Assigns a previously constructed Component to an Entity::Id.
*
* @returns component
*/
template <typename C>
- boost::shared_ptr<C> assign(Entity entity, boost::shared_ptr<C> component) {
+ boost::shared_ptr<C> assign(Entity::Id entity, boost::shared_ptr<C> component) {
boost::shared_ptr<BaseComponent> base = boost::static_pointer_cast<BaseComponent>(component);
accomodate_component(C::family());
entity_components_.at(C::family()).at(entity) = base;
@@ -316,24 +345,24 @@ class EntityManager : boost::noncopyable {
}
/**
- * Assign a Component to an Entity, optionally passing through Component constructor arguments.
+ * Assign a Component to an Entity::Id, optionally passing through Component constructor arguments.
*
* shared_ptr<Position> position = em.assign<Position>(e, x, y);
*
* @returns Newly created component.
*/
template <typename C, typename ... Args>
- boost::shared_ptr<C> assign(Entity entity, Args && ... args) {
+ boost::shared_ptr<C> assign(Entity::Id entity, Args && ... args) {
return assign<C>(entity, boost::make_shared<C>(args ...));
}
/**
- * Retrieve a Component assigned to an Entity.
+ * Retrieve a Component assigned to an Entity::Id.
*
- * @returns Component instance, or empty shared_ptr<> if the Entity does not have that Component.
+ * @returns Component instance, or empty shared_ptr<> if the Entity::Id does not have that Component.
*/
template <typename C>
- boost::shared_ptr<C> component(Entity id) {
+ boost::shared_ptr<C> component(Entity::Id id) {
// We don't bother checking the component mask, as we return a nullptr anyway.
if (C::family() >= entity_components_.size()) {
return boost::shared_ptr<C>();
@@ -374,7 +403,7 @@ class EntityManager : boost::noncopyable {
* unpack<Position, Direction>(e, p, d);
*/
template <typename A>
- void unpack(Entity id, boost::shared_ptr<A> &a) {
+ void unpack(Entity::Id id, boost::shared_ptr<A> &a) {
a = component<A>(id);
}
@@ -390,7 +419,7 @@ class EntityManager : boost::noncopyable {
* unpack<Position, Direction>(e, p, d);
*/
template <typename A, typename B, typename ... Args>
- void unpack(Entity id, boost::shared_ptr<A> &a, boost::shared_ptr<B> &b, Args && ... args) {
+ void unpack(Entity::Id id, boost::shared_ptr<A> &a, boost::shared_ptr<B> &b, Args && ... args) {
unpack<A>(id, a);
unpack<B, Args ...>(id, b, args ...);
}
@@ -416,7 +445,7 @@ class EntityManager : boost::noncopyable {
return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
}
- inline void accomodate_entity(Entity entity) {
+ inline void accomodate_entity(Entity::Id entity) {
if (entity_component_mask_.size() <= entity) {
entity_component_mask_.resize(entity + 1);
for (auto &components : entity_components_) {
@@ -434,15 +463,40 @@ class EntityManager : boost::noncopyable {
}
}
- Entity id_counter_ = 0;
+ Entity::Id id_counter_ = 0;
EventManager &event_manager_;
// A nested array of: components = entity_components_[family][entity]
std::vector<EntitiesComponent> entity_components_;
- // Bitmask of components associated with each entity. Index into the vector is the Entity.
+ // Bitmask of components associated with each entity. Index into the vector is the Entity::Id.
std::vector<uint64_t> entity_component_mask_;
- // List of available Entity IDs.
- boost::unordered_set<Entity> free_list_;
+ // List of available Entity::Id IDs.
+ boost::unordered_set<Entity::Id> free_list_;
};
+template <typename C>
+boost::shared_ptr<C> Entity::assign(boost::shared_ptr<C> component) {
+ return entities_.assign<C>(id_, component);
+}
+
+template <typename C, typename ... Args>
+boost::shared_ptr<C> Entity::assign(Args && ... args) {
+ return entities_.assign<C>(id_, args ...);
+}
+
+template <typename C>
+boost::shared_ptr<C> Entity::component() {
+ return entities_.component<C>(id_);
+}
+
+template <typename A>
+void Entity::unpack(boost::shared_ptr<A> &a) {
+ entities_.unpack(id_, a);
+}
+
+template <typename A, typename B, typename ... Args>
+void Entity::unpack(boost::shared_ptr<A> &a, boost::shared_ptr<B> &b, Args && ... args) {
+ entities_.unpack(id_, a, b, args ...);
+}
+
}
diff --git a/entityx/Entity_test.cc b/entityx/Entity_test.cc
index 1433b26..55da405 100644
--- a/entityx/Entity_test.cc
+++ b/entityx/Entity_test.cc
@@ -79,8 +79,9 @@ TEST_F(EntityManagerTest, TestCreateEntity) {
TEST_F(EntityManagerTest, TestComponentConstruction) {
auto e = em.create();
- auto p = em.assign<Position>(e, 1, 2);
- auto cp = em.component<Position>(e);
+ auto p = e.assign<Position>(1, 2);
+ //auto p = em.assign<Position>(e, 1, 2);
+ auto cp = e.component<Position>();
ASSERT_EQ(p, cp);
ASSERT_FLOAT_EQ(1.0, cp->x);
ASSERT_FLOAT_EQ(2.0, cp->y);
@@ -88,8 +89,8 @@ TEST_F(EntityManagerTest, TestComponentConstruction) {
TEST_F(EntityManagerTest, TestComponentCreationWithObject) {
auto e = em.create();
- auto p = em.assign(e, make_shared<Position>(1.0, 2.0));
- auto cp = em.component<Position>(e);
+ auto p = e.assign(make_shared<Position>(1.0, 2.0));
+ auto cp = e.component<Position>();
ASSERT_EQ(p, cp);
ASSERT_FLOAT_EQ(1.0, cp->x);
ASSERT_FLOAT_EQ(2.0, cp->y);
@@ -98,27 +99,27 @@ TEST_F(EntityManagerTest, TestComponentCreationWithObject) {
TEST_F(EntityManagerTest, TestDestroyEntity) {
Entity e = em.create();
Entity f = em.create();
- auto ep = em.assign<Position>(e);
- em.assign<Position>(f);
- em.assign<Direction>(e);
- em.assign<Direction>(f);
+ auto ep = e.assign<Position>();
+ f.assign<Position>();
+ e.assign<Direction>(e);
+ f.assign<Direction>();
ASSERT_EQ(2, ep.use_count());
ASSERT_TRUE(em.exists(e));
ASSERT_TRUE(em.exists(f));
- ASSERT_TRUE(em.component<Position>(e));
- ASSERT_TRUE(em.component<Direction>(e));
- ASSERT_TRUE(em.component<Position>(f));
- ASSERT_TRUE(em.component<Direction>(f));
+ ASSERT_TRUE(e.component<Position>());
+ ASSERT_TRUE(e.component<Direction>());
+ ASSERT_TRUE(f.component<Position>());
+ ASSERT_TRUE(f.component<Direction>());
em.destroy(e);
ASSERT_FALSE(em.exists(e));
ASSERT_TRUE(em.exists(f));
- ASSERT_FALSE(em.component<Position>(e));
- ASSERT_FALSE(em.component<Direction>(e));
- ASSERT_TRUE(em.component<Position>(f));
- ASSERT_TRUE(em.component<Direction>(f));
+ ASSERT_FALSE(e.component<Position>());
+ ASSERT_FALSE(e.component<Direction>());
+ ASSERT_TRUE(f.component<Position>());
+ ASSERT_TRUE(f.component<Direction>());
ASSERT_EQ(1, ep.use_count());
}
@@ -126,23 +127,23 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponent) {
Entity e = em.create();
Entity f = em.create();
Entity g = em.create();
- em.assign<Position>(e);
- em.assign<Direction>(e);
- em.assign<Position>(f);
- em.assign<Position>(g);
+ e.assign<Position>();
+ e.assign<Direction>();
+ f.assign<Position>();
+ g.assign<Position>();
ASSERT_EQ(3, size(em.entities_with_components<Position>()));
ASSERT_EQ(1, size(em.entities_with_components<Direction>()));
}
TEST_F(EntityManagerTest, TestGetEntitiesWithIntersectionOfComponents) {
- vector<Entity> entities;
+ vector<Entity::Id> entities;
for (int i = 0; i < 150; ++i) {
Entity e = em.create();
entities.push_back(e);
if (i % 2 == 0)
- em.assign<Position>(e);
+ e.assign<Position>();
if (i % 3 == 0)
- em.assign<Direction>(e);
+ e.assign<Direction>();
}
ASSERT_EQ(50, size(em.entities_with_components<Direction>()));
@@ -151,10 +152,10 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithIntersectionOfComponents) {
}
TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
- vector<Entity> entities;
- Entity e = em.create();
- Entity f = em.create();
- Entity g = em.create();
+ vector<Entity::Id> entities;
+ Entity::Id e = em.create();
+ Entity::Id f = em.create();
+ Entity::Id g = em.create();
std::vector<std::pair<shared_ptr<Position>, shared_ptr<Direction>>> position_directions;
position_directions.push_back(std::make_pair(
em.assign<Position>(e, 1.0f, 2.0f),
@@ -180,7 +181,7 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
}
TEST_F(EntityManagerTest, TestUnpack) {
- Entity e = em.create();
+ Entity::Id e = em.create();
auto p = em.assign<Position>(e);
auto d = em.assign<Direction>(e);
@@ -192,7 +193,7 @@ TEST_F(EntityManagerTest, TestUnpack) {
}
TEST_F(EntityManagerTest, TestUnpackNullMissing) {
- Entity e = em.create();
+ Entity::Id e = em.create();
auto p = em.assign<Position>(e);
struct NullDeleter {template<typename T> void operator()(T*) {} };
@@ -213,7 +214,7 @@ TEST_F(EntityManagerTest, TestEntityCreatedEvent) {
created.push_back(event.entity);
}
- vector<Entity> created;
+ vector<Entity::Id> created;
};
EntityCreatedEventReceiver receiver;
@@ -232,14 +233,14 @@ TEST_F(EntityManagerTest, TestEntityDestroyedEvent) {
destroyed.push_back(event.entity);
}
- vector<Entity> destroyed;
+ vector<Entity::Id> destroyed;
};
EntityDestroyedEventReceiver receiver;
ev.subscribe<EntityDestroyedEvent>(receiver);
ASSERT_EQ(0, receiver.destroyed.size());
- vector<Entity> entities;
+ vector<Entity::Id> entities;
for (int i = 0; i < 10; ++i) {
entities.push_back(em.create());
}
@@ -282,7 +283,7 @@ TEST_F(EntityManagerTest, TestComponentAddedEvent) {
ASSERT_EQ(0, receiver.position_events);
ASSERT_EQ(0, receiver.direction_events);
for (int i = 0; i < 10; ++i) {
- Entity e = em.create();
+ Entity::Id e = em.create();
em.assign<Position>(e, float(i), float(i));
em.assign<Direction>(e, float(-i), float(-i));
}
diff --git a/entityx/System_test.cc b/entityx/System_test.cc
index 42312d3..63da01f 100644
--- a/entityx/System_test.cc
+++ b/entityx/System_test.cc
@@ -54,7 +54,7 @@ class MovementSystem : public System<MovementSystem> {
class TestManager : public entityx::Manager {
public:
- std::vector<Entity> entities;
+ std::vector<Entity::Id> entities;
SystemManager &sm() { return system_manager; }
EntityManager &em() { return entity_manager; }
@@ -65,7 +65,7 @@ class TestManager : public entityx::Manager {
void initialize() override {
for (int i = 0; i < 150; ++i) {
- Entity e = entity_manager.create();
+ Entity::Id e = entity_manager.create();
entities.push_back(e);
if (i % 2 == 0)
entity_manager.assign<Position>(e, 1, 2);