aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlec Thomas <alec@swapoff.org>2013-09-04 19:36:31 -0400
committerAlec Thomas <alec@swapoff.org>2013-09-04 19:36:31 -0400
commit7a580c4be6dc0207c05e2cdb8fb89211c4a1113b (patch)
treea141d1fc32fe82d716b5d08b8e75eb42c95344a0
parentb02261bd25a5fc307dd6b9f8fd0a87fb2d3d91f1 (diff)
Performance improvements + emitting events from Python.
-rw-r--r--CMakeLists.txt7
-rw-r--r--README.md33
-rw-r--r--entityx/Benchmarks_test.cc10
-rw-r--r--entityx/Entity.cc8
-rw-r--r--entityx/Entity.h211
-rw-r--r--entityx/Entity_test.cc42
-rw-r--r--entityx/Event.cc13
-rw-r--r--entityx/Event.h49
-rw-r--r--entityx/Event_test.cc11
-rw-r--r--entityx/Manager.h17
-rw-r--r--entityx/ReferenceCounted.h0
-rw-r--r--entityx/System.h54
-rw-r--r--entityx/System_test.cc16
-rw-r--r--entityx/config.h.in63
-rw-r--r--entityx/python/PythonSystem.cc86
-rw-r--r--entityx/python/PythonSystem.h74
-rw-r--r--entityx/python/PythonSystem_test.cc85
-rw-r--r--entityx/python/README.md8
-rw-r--r--entityx/python/entityx/__init__.py10
-rw-r--r--entityx/python/entityx/tests/event_emit_test.py14
-rw-r--r--entityx/python/entityx/tests/update_test.py2
-rw-r--r--entityx/tags/TagsComponent.h12
22 files changed, 505 insertions, 320 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 667549f..761a031 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,7 @@ set(ENTITYX_USE_CPP11_STDLIB false CACHE BOOL "For Clang, specify whether to use
set(ENTITYX_USE_STD_SHARED_PTR false CACHE BOOL "Use std::shared_ptr<T> rather than boost::shared_ptr<T>?")
set(ENTITYX_BUILD_SHARED true CACHE BOOL "Build shared libraries?")
set(ENTITYX_BUILD_PYTHON true CACHE BOOL "Build entityx::python?")
+set(ENTITYX_BOOST_SP_DISABLE_THREADS false CACHE BOOL "Disable multi-threading support in boost::shared_ptr")
include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
include(CheckCXXSourceCompiles)
@@ -27,6 +28,12 @@ set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
+
+if (ENTITYX_BOOST_SP_DISABLE_THREADS)
+ message("-- Disabled multi-threading support in Boost (see http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm)")
+ add_definitions(-DBOOST_SP_DISABLE_THREADS=1)
+endif ()
+
# C++11 feature checks
include(CheckCXX11Features.cmake)
diff --git a/README.md b/README.md
index 49b03c6..f60897b 100644
--- a/README.md
+++ b/README.md
@@ -38,8 +38,8 @@ An `Entity` is a convenience class wrapping an opaque `uint64_t` value allocated
Creating an entity is as simple as:
```c++
-entityx::shared_ptr<EventManager> events = EventManager::make();
-entityx::shared_ptr<EntityManager> entities = EntityManager::make(events);
+entityx::ptr<EventManager> events = EventManager::make();
+entityx::ptr<EntityManager> entities = EntityManager::make(events);
Entity entity = entities->create();
```
@@ -57,6 +57,7 @@ entity.destroy();
- When an entity is destroyed the manager adds its ID to a free list and invalidates the Entity handle.
- When an entity is created IDs are recycled from the free list before allocating new ones.
- An Entity ID contains an index and a version. When an entity is destroyed, the version associated with the index is incremented, invalidating all previous entities referencing the previous ID.
+- EntityX uses a reference counting smart pointer`entityx::ptr<T>` to manage object lifetimes. As a general rule, passing a pointer to any EntityX method will convert to a smart pointer and take ownership. To maintain your own reference to the pointer you will need to wrap it in `entityx::ptr<T>`.
### Components (entity data)
@@ -94,7 +95,7 @@ entity.assign<Position>(1.0f, 2.0f);
You can also assign existing instances of components:
```c++
-entityx::shared_ptr<Position> position = entityx::make_shared<Position>(1.0f, 2.0f);
+entityx::ptr<Position> position = new Position(1.0f, 2.0f);
entity.assign(position);
```
@@ -104,8 +105,8 @@ To query all entities with a set of components assigned, use ``EntityManager::en
```c++
for (auto entity : entities->entities_with_components<Position, Direction>()) {
- entityx::shared_ptr<Position> position = entity.component<Position>();
- entityx::shared_ptr<Direction> direction = entity.component<Direction>();
+ entityx::ptr<Position> position = entity.component<Position>();
+ entityx::ptr<Direction> direction = entity.component<Direction>();
// Do things with entity, position and direction.
}
@@ -114,7 +115,7 @@ for (auto entity : entities->entities_with_components<Position, Direction>()) {
To retrieve a component associated with an entity use ``Entity::component<C>()``:
```c++
-entityx::shared_ptr<Position> position = entity.component<Position>();
+entityx::ptr<Position> position = entity.component<Position>();
if (position) {
// Do stuff with position
}
@@ -133,10 +134,10 @@ A basic movement system might be implemented with something like the following:
```c++
struct MovementSystem : public System<MovementSystem> {
- void update(entityx::shared_ptr<EntityManager> es, entityx::shared_ptr<EventManager> events, double dt) override {
+ void update(entityx::ptr<EntityManager> es, entityx::ptr<EventManager> events, double dt) override {
for (auto entity : es->entities_with_components<Position, Direction>()) {
- entityx::shared_ptr<Position> position = entity.component<Position>();
- entityx::shared_ptr<Direction> direction = entity.component<Direction>();
+ entityx::ptr<Position> position = entity.component<Position>();
+ entityx::ptr<Direction> direction = entity.component<Direction>();
position->x += direction->x * dt;
position->y += direction->y * dt;
@@ -171,10 +172,10 @@ Next we implement our collision system, which emits ``Collision`` objects via an
```c++
class CollisionSystem : public System<CollisionSystem> {
public:
- void update(entityx::shared_ptr<EntityManager> es, entityx::shared_ptr<EventManager> events, double dt) override {
- entityx::shared_ptr<Position> left_position, right_position;
- for (auto left_entity : es.entities_with_components<Position>()) {
- for (auto right_entity : es.entities_with_components<Position>()) {
+ void update(entityx::ptr<EntityManager> es, entityx::ptr<EventManager> events, double dt) override {
+ entityx::ptr<Position> left_position, right_position;
+ for (auto left_entity : es.entities_with_components<Position>(left_position)) {
+ for (auto right_entity : es.entities_with_components<Position>(right_position)) {
if (collide(left_position, right_position)) {
events.emit<Collision>(left_entity, right_entity);
}
@@ -190,8 +191,8 @@ Objects interested in receiving collision information can subscribe to ``Collisi
```c++
struct DebugSystem : public System<DebugSystem>, Receiver<DebugSystem> {
- void configure(EventManager &event_manager) {
- event_manager.subscribe<Collision>(*this);
+ void configure(entityx::ptr<EventManager> event_manager) {
+ event_manager->subscribe<Collision>(*this);
}
void receive(const Collision &collision) {
@@ -210,7 +211,7 @@ Several events are emitted by EntityX itself:
- `Entity entity` - Entity about to be destroyed.
- `ComponentAddedEvent<T>` - emitted when a new component is added to an entity.
- `Entity entity` - Entity that component was added to.
- - `entityx::shared_ptr<T> component` - The component added.
+ - `entityx::ptr<T> component` - The component added.
#### Implementation notes
diff --git a/entityx/Benchmarks_test.cc b/entityx/Benchmarks_test.cc
index d02896a..f469c37 100644
--- a/entityx/Benchmarks_test.cc
+++ b/entityx/Benchmarks_test.cc
@@ -9,10 +9,10 @@ using namespace entityx;
class BenchmarksTest : public ::testing::Test {
protected:
- BenchmarksTest() : ev(EventManager::make()), em(EntityManager::make(ev)) {}
+ BenchmarksTest() : ev(EventManager::make()), em(EntityManager::make(ev)) {}
- entityx::shared_ptr<EventManager> ev;
- entityx::shared_ptr<EntityManager> em;
+ ptr<EventManager> ev;
+ ptr<EntityManager> em;
};
@@ -97,8 +97,8 @@ TEST_F(BenchmarksTest, TestEntityIteration) {
cout << "iterating over " << count << " entities with a component 10 times" << endl;
for (int i = 0; i < 10; ++i) {
- for (auto e : em->entities_with_components<Position>()) {
- entityx::shared_ptr<Position> position = e.component<Position>();
+ ptr<Position> position;
+ for (auto e : em->entities_with_components<Position>(position)) {
position.get();
}
}
diff --git a/entityx/Entity.cc b/entityx/Entity.cc
index 31eb254..dfc6bb5 100644
--- a/entityx/Entity.cc
+++ b/entityx/Entity.cc
@@ -31,6 +31,12 @@ bool Entity::valid() const {
return !manager_.expired() && manager_.lock()->valid(id_);
}
+EntityManager::EntityManager(ptr<EventManager> event_manager) : event_manager_(event_manager) {
+}
+
+EntityManager::~EntityManager() {
+}
+
void EntityManager::destroy_all() {
entity_components_.clear();
entity_component_mask_.clear();
@@ -39,4 +45,4 @@ void EntityManager::destroy_all() {
}
-}
+} // namespace entityx
diff --git a/entityx/Entity.h b/entityx/Entity.h
index 09cff22..abb3552 100644
--- a/entityx/Entity.h
+++ b/entityx/Entity.h
@@ -53,12 +53,12 @@ public:
bool operator != (const Id &other) const { return id_ != other.id_; }
bool operator < (const Id &other) const { return id_ < other.id_; }
- private:
- friend class EntityManager;
-
uint32_t index() const { return id_ & 0xffffffffUL; }
uint32_t version() const { return id_ >> 32; }
+ private:
+ friend class EntityManager;
+
uint64_t id_;
};
@@ -76,12 +76,12 @@ public:
/**
* Check if Entity handle is invalid.
*/
- bool operator !() const {
- return !valid();
+ operator bool () const {
+ return valid();
}
bool operator == (const Entity &other) const {
- return other.manager_.lock() == manager_.lock() && other.id_ == id_;
+ return other.manager_ == manager_ && other.id_ == id_;
}
bool operator != (const Entity &other) const {
@@ -109,20 +109,20 @@ public:
Id id() const { return id_; }
template <typename C>
- entityx::shared_ptr<C> assign(entityx::shared_ptr<C> component);
+ ptr<C> assign(ptr<C> component);
template <typename C, typename ... Args>
- entityx::shared_ptr<C> assign(Args && ... args);
+ ptr<C> assign(Args && ... args);
template <typename C>
- entityx::shared_ptr<C> remove();
+ ptr<C> remove();
template <typename C>
- entityx::shared_ptr<C> component();
+ ptr<C> component();
template <typename A>
- void unpack(entityx::shared_ptr<A> &a);
+ void unpack(ptr<A> &a);
template <typename A, typename B, typename ... Args>
- void unpack(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args);
+ void unpack(ptr<A> &a, ptr<B> &b, Args && ... args);
/**
* Destroy and invalidate this Entity.
@@ -132,9 +132,9 @@ public:
private:
friend class EntityManager;
- Entity(entityx::shared_ptr<EntityManager> manager, Entity::Id id) : manager_(manager), id_(id) {}
+ Entity(ptr<EntityManager> manager, Entity::Id id) : manager_(manager), id_(id) {}
- entityx::weak_ptr<EntityManager> manager_;
+ weak_ptr<EntityManager> manager_;
Entity::Id id_ = INVALID;
};
@@ -216,11 +216,11 @@ struct EntityDestroyedEvent : public Event<EntityDestroyedEvent> {
*/
template <typename T>
struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
- ComponentAddedEvent(Entity entity, entityx::shared_ptr<T> component) :
+ ComponentAddedEvent(Entity entity, ptr<T> component) :
entity(entity), component(component) {}
Entity entity;
- entityx::shared_ptr<T> component;
+ ptr<T> component;
};
/**
@@ -228,43 +228,52 @@ struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
*/
template <typename T>
struct ComponentRemovedEvent : public Event<ComponentRemovedEvent<T>> {
- ComponentRemovedEvent(Entity entity, entityx::shared_ptr<T> component) :
+ ComponentRemovedEvent(Entity entity, ptr<T> component) :
entity(entity), component(component) {}
Entity entity;
- entityx::shared_ptr<T> component;
+ ptr<T> component;
};
/**
* Manages Entity::Id creation and component assignment.
*/
-class EntityManager : public entityx::enable_shared_from_this<EntityManager>, boost::noncopyable {
+class EntityManager : boost::noncopyable, public enable_shared_from_this<EntityManager> {
public:
typedef std::bitset<entityx::MAX_COMPONENTS> ComponentMask;
- static entityx::shared_ptr<EntityManager> make(entityx::shared_ptr<EventManager> event_manager) {
- return entityx::shared_ptr<EntityManager>(new EntityManager(event_manager));
+ explicit EntityManager(ptr<EventManager> event_manager);
+ virtual ~EntityManager();
+
+ static ptr<EntityManager> make(ptr<EventManager> event_manager) {
+ return ptr<EntityManager>(new EntityManager(event_manager));
}
class View {
public:
- typedef boost::function<bool (entityx::shared_ptr<EntityManager>, Entity::Id)> Predicate;
+ typedef boost::function<bool (const ptr<EntityManager> &, const Entity::Id &)> Predicate;
/// A predicate that matches valid entities with the given component mask.
class ComponentMaskPredicate {
public:
- ComponentMaskPredicate(const std::vector<ComponentMask> &entity_id, ComponentMask mask) : entity_id_(entity_id), mask_(mask) {}
+ ComponentMaskPredicate(const std::vector<ComponentMask> &entity_components, ComponentMask mask)
+ : entity_components_(entity_components), mask_(mask) {}
- bool operator()(entityx::shared_ptr<EntityManager> entities, Entity::Id entity) {
- return entities->entity_version_.at(entity.index()) == entity.version()
- && (entity_id_.at(entity.index()) & mask_) == mask_;
+ bool operator()(const ptr<EntityManager> &entities, const Entity::Id &entity) {
+ return entities->entity_version_[entity.index()] == entity.version()
+ && (entity_components_[entity.index()] & mask_) == mask_;
}
private:
- const std::vector<ComponentMask> &entity_id_;
+ const std::vector<ComponentMask> &entity_components_;
ComponentMask mask_;
};
+ struct BaseUnpacker {
+ virtual ~BaseUnpacker() {}
+ virtual void unpack(const Entity::Id &id) = 0;
+ };
+
/// An iterator over a view of the entities in an EntityManager.
class Iterator : public std::iterator<std::input_iterator_tag, Entity::Id> {
public:
@@ -275,40 +284,47 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
}
bool operator == (const Iterator& rhs) const { return i_ == rhs.i_; }
bool operator != (const Iterator& rhs) const { return i_ != rhs.i_; }
- Entity operator * () { return Entity(view_.manager_, view_.manager_->create_id(i_)); }
- const Entity operator * () const { return Entity(view_.manager_, view_.manager_->create_id(i_)); }
+ Entity operator * () { return Entity(manager_, manager_->create_id(i_)); }
+ const Entity operator * () const { return Entity(manager_, manager_->create_id(i_)); }
private:
friend class View;
- Iterator(const View &view, uint32_t index) : view_(view), i_(index) {
+ Iterator(ptr<EntityManager> manager,
+ std::vector<Predicate> predicates,
+ std::vector<ptr<BaseUnpacker>> unpackers,
+ uint32_t index)
+ : manager_(manager), predicates_(predicates), unpackers_(unpackers), i_(index), capacity_(manager_->capacity()) {
next();
}
void next() {
- while (i_ < view_.manager_->capacity() && !predicate()) {
+ while (i_ < capacity_ && !predicate()) {
++i_;
}
- if (i_ < view_.manager_->capacity() && !view_.unpackers_.empty()) {
- Entity::Id id = view_.manager_->create_id(i_);
- for (auto &unpacker : view_.unpackers_) {
- unpacker(id);
+ if (i_ < capacity_ && !unpackers_.empty()) {
+ Entity::Id id = manager_->create_id(i_);
+ for (auto &unpacker : unpackers_) {
+ unpacker->unpack(id);
}
}
}
bool predicate() {
- Entity::Id id = view_.manager_->create_id(i_);
- for (auto &p : view_.predicates_) {
- if (!p(view_.manager_, id)) {
+ Entity::Id id = manager_->create_id(i_);
+ for (auto &p : predicates_) {
+ if (!p(manager_, id)) {
return false;
}
}
return true;
}
- const View &view_;
+ ptr<EntityManager> manager_;
+ std::vector<Predicate> predicates_;
+ std::vector<ptr<BaseUnpacker>> unpackers_;
uint32_t i_;
+ size_t capacity_;
};
// Create a sub-view with an additional predicate.
@@ -316,19 +332,19 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
predicates_.push_back(predicate);
}
- Iterator begin() { return Iterator(*this, 0); }
- Iterator end() { return Iterator(*this, manager_->size()); }
- const Iterator begin() const { return Iterator(*this, 0); }
- const Iterator end() const { return Iterator(*this, manager_->size()); }
+ Iterator begin() { return Iterator(manager_, predicates_, unpackers_, 0); }
+ Iterator end() { return Iterator(manager_, predicates_, unpackers_, manager_->size()); }
+ const Iterator begin() const { return Iterator(manager_, predicates_, unpackers_, 0); }
+ const Iterator end() const { return Iterator(manager_, predicates_, unpackers_, manager_->size()); }
template <typename A>
- View &unpack_to(entityx::shared_ptr<A> &a) {
- unpackers_.push_back(Unpacker<A>(manager_, a));
+ View &unpack_to(ptr<A> &a) {
+ unpackers_.push_back(ptr<Unpacker<A>>(new Unpacker<A>(manager_, a)));
return *this;
}
template <typename A, typename B, typename ... Args>
- View &unpack_to(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
+ View &unpack_to(ptr<A> &a, ptr<B> &b, Args && ... args) {
unpack_to<A>(a);
return unpack_to<B, Args ...>(b, args ...);
}
@@ -337,25 +353,25 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
friend class EntityManager;
template <typename T>
- struct Unpacker {
- Unpacker(entityx::shared_ptr<EntityManager> manager, entityx::shared_ptr<T> &c) : manager_(manager), c(c) {}
+ struct Unpacker : BaseUnpacker {
+ Unpacker(ptr<EntityManager> manager, ptr<T> &c) : manager_(manager), c(c) {}
- void operator()(Entity::Id id) {
+ void unpack(const Entity::Id &id) {
c = manager_->component<T>(id);
}
private:
- entityx::shared_ptr<EntityManager> manager_;
- entityx::shared_ptr<T> &c;
+ ptr<EntityManager> manager_;
+ ptr<T> &c;
};
- View(entityx::shared_ptr<EntityManager> manager, Predicate predicate) : manager_(manager) {
+ View(ptr<EntityManager> manager, Predicate predicate) : manager_(manager) {
predicates_.push_back(predicate);
}
- entityx::shared_ptr<EntityManager> manager_;
+ ptr<EntityManager> manager_;
std::vector<Predicate> predicates_;
- std::vector<boost::function<void(Entity::Id)>> unpackers_;
+ std::vector<ptr<BaseUnpacker>> unpackers_;
};
/**
@@ -372,7 +388,7 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
* Return true if the given entity ID is still valid.
*/
bool valid(Entity::Id id) {
- return id.index() < entity_version_.size() && entity_version_.at(id.index()) == id.version();
+ return id.index() < entity_version_.size() && entity_version_[id.index()] == id.version();
}
/**
@@ -385,11 +401,11 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
if (free_list_.empty()) {
index = index_counter_++;
accomodate_entity(index);
- version = entity_version_.at(index) = 1;
+ version = entity_version_[index] = 1;
} else {
index = free_list_.front();
free_list_.pop_front();
- version = entity_version_.at(index);
+ version = entity_version_[index];
}
Entity entity(shared_from_this(), Entity::Id(index, version));
event_manager_->emit<EntityCreatedEvent>(entity);
@@ -403,18 +419,18 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
*/
void destroy(Entity::Id entity) {
assert(entity.index() < entity_component_mask_.size() && "Entity::Id ID outside entity vector range");
- assert(entity_version_.at(entity.index()) == entity.version() && "Attempt to destroy Entity using a stale Entity::Id");
+ assert(entity_version_[entity.index()] == entity.version() && "Attempt to destroy Entity using a stale Entity::Id");
event_manager_->emit<EntityDestroyedEvent>(Entity(shared_from_this(), entity));
for (auto &components : entity_components_) {
- components.at(entity.index()).reset();
+ components[entity.index()].reset();
}
- entity_component_mask_.at(entity.index()) = 0;
- entity_version_.at(entity.index())++;
+ entity_component_mask_[entity.index()] = 0;
+ entity_version_[entity.index()]++;
free_list_.push_back(entity.index());
}
Entity get(Entity::Id id) {
- assert(entity_version_.at(id.index()) != id.version() && "Attempt to get() with stale Entity::Id");
+ assert(entity_version_[id.index()] != id.version() && "Attempt to get() with stale Entity::Id");
return Entity(shared_from_this(), id);
}
@@ -425,7 +441,7 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
* fail if the ID is invalid.
*/
Entity::Id create_id(uint32_t index) const {
- return Entity::Id(index, entity_version_.at(index));
+ return Entity::Id(index, entity_version_[index]);
}
/**
@@ -434,11 +450,11 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
* @returns component
*/
template <typename C>
- entityx::shared_ptr<C> assign(Entity::Id id, entityx::shared_ptr<C> component) {
- entityx::shared_ptr<BaseComponent> base = entityx::static_pointer_cast<BaseComponent>(component);
+ ptr<C> assign(Entity::Id id, ptr<C> component) {
+ ptr<BaseComponent> base(static_pointer_cast<BaseComponent>(component));
accomodate_component(C::family());
- entity_components_.at(C::family()).at(id.index()) = base;
- entity_component_mask_.at(id.index()) |= uint64_t(1) << C::family();
+ entity_components_[C::family()][id.index()] = base;
+ entity_component_mask_[id.index()] |= uint64_t(1) << C::family();
event_manager_->emit<ComponentAddedEvent<C>>(Entity(shared_from_this(), id), component);
return component;
@@ -447,13 +463,13 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
/**
* Assign a Component to an Entity::Id, optionally passing through Component constructor arguments.
*
- * shared_ptr<Position> position = em.assign<Position>(e, x, y);
+ * ptr<Position> position = em.assign<Position>(e, x, y);
*
* @returns Newly created component.
*/
template <typename C, typename ... Args>
- entityx::shared_ptr<C> assign(Entity::Id entity, Args && ... args) {
- return assign<C>(entity, entityx::make_shared<C>(args ...));
+ ptr<C> assign(Entity::Id entity, Args && ... args) {
+ return assign<C>(entity, ptr<C>(new C(args ...)));
}
/**
@@ -462,10 +478,10 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
* Emits a ComponentRemovedEvent<C> event.
*/
template <typename C>
- entityx::shared_ptr<C> remove(Entity::Id id) {
- entityx::shared_ptr<C> component = entityx::static_pointer_cast<C>(entity_components_.at(C::family()).at(id.index()));
- entity_components_.at(C::family()).at(id.index()).reset();
- entity_component_mask_.at(id.index()) &= ~(uint64_t(1) << C::family());
+ ptr<C> remove(const Entity::Id &id) {
+ ptr<C> component(static_pointer_cast<C>(entity_components_[C::family()][id.index()]));
+ entity_components_[C::family()][id.index()].reset();
+ entity_component_mask_[id.index()] &= ~(uint64_t(1) << C::family());
if (component)
event_manager_->emit<ComponentRemovedEvent<C>>(Entity(shared_from_this(), id), component);
return component;
@@ -474,16 +490,16 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
/**
* Retrieve a Component assigned to an Entity::Id.
*
- * @returns Component instance, or empty shared_ptr<> if the Entity::Id does not have that Component.
+ * @returns Component instance, or empty ptr<> if the Entity::Id does not have that Component.
*/
template <typename C>
- entityx::shared_ptr<C> component(Entity::Id id) {
+ ptr<C> component(const Entity::Id &id) {
// We don't bother checking the component mask, as we return a nullptr anyway.
if (C::family() >= entity_components_.size()) {
- return entityx::shared_ptr<C>();
+ return ptr<C>();
}
- entityx::shared_ptr<BaseComponent> c = entity_components_.at(C::family()).at(id.index());
- return entityx::static_pointer_cast<C>(c);
+ ptr<BaseComponent> c = entity_components_[C::family()][id.index()];
+ return ptr<C>(static_pointer_cast<C>(c));
}
/**
@@ -499,7 +515,7 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
* Find Entities that have all of the specified Components.
*/
template <typename C, typename ... Components>
- View entities_with_components(entityx::shared_ptr<C> &c, Components && ... args) {
+ View entities_with_components(ptr<C> &c, Components && ... args) {
auto mask = component_mask(c, args ...);
return
View(shared_from_this(), View::ComponentMaskPredicate(entity_component_mask_, mask))
@@ -513,12 +529,12 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
*
* Useful for fast bulk iterations.
*
- * entityx::shared_ptr<Position> p;
- * entityx::shared_ptr<Direction> d;
+ * ptr<Position> p;
+ * ptr<Direction> d;
* unpack<Position, Direction>(e, p, d);
*/
template <typename A>
- void unpack(Entity::Id id, entityx::shared_ptr<A> &a) {
+ void unpack(Entity::Id id, ptr<A> &a) {
a = component<A>(id);
}
@@ -529,12 +545,12 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
*
* Useful for fast bulk iterations.
*
- * entityx::shared_ptr<Position> p;
- * entityx::shared_ptr<Direction> d;
+ * ptr<Position> p;
+ * ptr<Direction> d;
* unpack<Position, Direction>(e, p, d);
*/
template <typename A, typename B, typename ... Args>
- void unpack(Entity::Id id, entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
+ void unpack(Entity::Id id, ptr<A> &a, ptr<B> &b, Args && ... args) {
unpack<A>(id, a);
unpack<B, Args ...>(id, b, args ...);
}
@@ -545,9 +561,6 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
void destroy_all();
private:
- explicit EntityManager(entityx::shared_ptr<EventManager> event_manager) : event_manager_(event_manager) {}
-
-
template <typename C>
ComponentMask component_mask() {
ComponentMask mask;
@@ -561,12 +574,12 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
}
template <typename C>
- ComponentMask component_mask(const entityx::shared_ptr<C> &c) {
+ ComponentMask component_mask(const ptr<C> &c) {
return component_mask<C>();
}
template <typename C1, typename C2, typename ... Components>
- ComponentMask component_mask(const entityx::shared_ptr<C1> &c1, const entityx::shared_ptr<C2> &c2, Components && ... args) {
+ ComponentMask component_mask(const ptr<C1> &c1, const ptr<C2> &c2, Components && ... args) {
return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
}
@@ -591,9 +604,9 @@ class EntityManager : public entityx::enable_shared_from_this<EntityManager>, bo
uint32_t index_counter_ = 0;
- entityx::shared_ptr<EventManager> event_manager_;
+ ptr<EventManager> event_manager_;
// A nested array of: components = entity_components_[family][entity]
- std::vector<std::vector<entityx::shared_ptr<BaseComponent>>> entity_components_;
+ std::vector<std::vector<ptr<BaseComponent>>> entity_components_;
// Bitmask of components associated with each entity. Index into the vector is the Entity::Id.
std::vector<ComponentMask> entity_component_mask_;
// Vector of entity version numbers. Incremented each time an entity is destroyed
@@ -610,37 +623,37 @@ BaseComponent::Family Component<C>::family() {
}
template <typename C>
-entityx::shared_ptr<C> Entity::assign(entityx::shared_ptr<C> component) {
+ptr<C> Entity::assign(ptr<C> component) {
assert(valid());
return manager_.lock()->assign<C>(id_, component);
}
template <typename C, typename ... Args>
-entityx::shared_ptr<C> Entity::assign(Args && ... args) {
+ptr<C> Entity::assign(Args && ... args) {
assert(valid());
return manager_.lock()->assign<C>(id_, args ...);
}
template <typename C>
-entityx::shared_ptr<C> Entity::remove(){
+ptr<C> Entity::remove() {
assert(valid() && component<C>());
return manager_.lock()->remove<C>(id_);
}
template <typename C>
-entityx::shared_ptr<C> Entity::component() {
+ptr<C> Entity::component() {
assert(valid());
return manager_.lock()->component<C>(id_);
}
template <typename A>
-void Entity::unpack(entityx::shared_ptr<A> &a) {
+void Entity::unpack(ptr<A> &a) {
assert(valid());
manager_.lock()->unpack(id_, a);
}
template <typename A, typename B, typename ... Args>
-void Entity::unpack(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
+void Entity::unpack(ptr<A> &a, ptr<B> &b, Args && ... args) {
assert(valid());
manager_.lock()->unpack(id_, a, b, args ...);
}
diff --git a/entityx/Entity_test.cc b/entityx/Entity_test.cc
index e207ade..701c15b 100644
--- a/entityx/Entity_test.cc
+++ b/entityx/Entity_test.cc
@@ -66,8 +66,8 @@ class EntityManagerTest : public ::testing::Test {
protected:
EntityManagerTest() : ev(EventManager::make()), em(EntityManager::make(ev)) {}
- entityx::shared_ptr<EventManager> ev;
- entityx::shared_ptr<EntityManager> em;
+ ptr<EventManager> ev;
+ ptr<EntityManager> em;
virtual void SetUp() {
}
@@ -125,7 +125,6 @@ TEST_F(EntityManagerTest, TestEntityReuse) {
TEST_F(EntityManagerTest, TestComponentConstruction) {
auto e = em->create();
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);
@@ -134,7 +133,7 @@ TEST_F(EntityManagerTest, TestComponentConstruction) {
TEST_F(EntityManagerTest, TestComponentCreationWithObject) {
auto e = em->create();
- auto p = e.assign(entityx::make_shared<Position>(1.0, 2.0));
+ auto p = e.assign(ptr<Position>(new Position(1.0, 2.0)));
auto cp = e.component<Position>();
ASSERT_EQ(p, cp);
ASSERT_FLOAT_EQ(1.0, cp->x);
@@ -149,7 +148,7 @@ TEST_F(EntityManagerTest, TestDestroyEntity) {
e.assign<Direction>();
f.assign<Direction>();
- ASSERT_EQ(2, ep.use_count());
+ ASSERT_EQ(2, use_count(ep));
ASSERT_TRUE(e.valid());
ASSERT_TRUE(f.valid());
ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
@@ -163,7 +162,7 @@ TEST_F(EntityManagerTest, TestDestroyEntity) {
ASSERT_TRUE(f.valid());
ASSERT_TRUE(static_cast<bool>(f.component<Position>()));
ASSERT_TRUE(static_cast<bool>(f.component<Direction>()));
- ASSERT_EQ(1, ep.use_count());
+ ASSERT_EQ(1, use_count(ep));
}
TEST_F(EntityManagerTest, TestGetEntitiesWithComponent) {
@@ -198,7 +197,7 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
Entity e = em->create();
Entity f = em->create();
Entity g = em->create();
- std::vector<std::pair<entityx::shared_ptr<Position>, entityx::shared_ptr<Direction>>> position_directions;
+ std::vector<std::pair<ptr<Position>, ptr<Direction>>> position_directions;
position_directions.push_back(std::make_pair(
e.assign<Position>(1.0f, 2.0f),
e.assign<Direction>(3.0f, 4.0f)));
@@ -208,8 +207,8 @@ TEST_F(EntityManagerTest, TestGetEntitiesWithComponentAndUnpacking) {
g.assign<Position>(5.0f, 6.0f);
int i = 0;
- entityx::shared_ptr<Position> position;
- entityx::shared_ptr<Direction> direction;
+ ptr<Position> position;
+ ptr<Direction> direction;
for (auto unused_entity : em->entities_with_components(position, direction)) {
(void)unused_entity;
ASSERT_TRUE(static_cast<bool>(position));
@@ -227,26 +226,25 @@ TEST_F(EntityManagerTest, TestUnpack) {
auto p = e.assign<Position>();
auto d = e.assign<Direction>();
- entityx::shared_ptr<Position> up;
- entityx::shared_ptr<Direction> ud;
+ ptr<Position> up;
+ ptr<Direction> ud;
e.unpack<Position, Direction>(up, ud);
ASSERT_EQ(p, up);
ASSERT_EQ(d, ud);
}
// gcc 4.7.2 does not allow this struct to be declared locally inside the TEST_F.
-struct NullDeleter {template<typename T> void operator()(T *unused) {} };
-TEST_F(EntityManagerTest, TestUnpackNullMissing) {
- Entity e = em->create();
- auto p = e.assign<Position>();
+// TEST_F(EntityManagerTest, TestUnpackNullMissing) {
+// Entity e = em->create();
+// auto p = e.assign<Position>();
- entityx::shared_ptr<Position> up(reinterpret_cast<Position*>(0Xdeadbeef), NullDeleter());
- entityx::shared_ptr<Direction> ud(reinterpret_cast<Direction*>(0Xdeadbeef), NullDeleter());
- e.unpack<Position, Direction>(up, ud);
- ASSERT_EQ(p, up);
- ASSERT_EQ(entityx::shared_ptr<Direction>(), ud);
-}
+// ptr<Position> up(reinterpret_cast<Position*>(0Xdeadbeef), NullDeleter());
+// ptr<Direction> ud(reinterpret_cast<Direction*>(0Xdeadbeef), NullDeleter());
+// e.unpack<Position, Direction>(up, ud);
+// ASSERT_EQ(p, up);
+// ASSERT_EQ(ptr<Direction>(), ud);
+// }
TEST_F(EntityManagerTest, TestComponentIdsDiffer) {
ASSERT_NE(Position::family(), Direction::family());
@@ -341,7 +339,7 @@ TEST_F(EntityManagerTest, TestComponentRemovedEvent) {
removed = event.component;
}
- entityx::shared_ptr<Direction> removed;
+ ptr<Direction> removed;
};
ComponentRemovedReceiver receiver;
diff --git a/entityx/Event.cc b/entityx/Event.cc
index 1dba40c..db73d79 100644
--- a/entityx/Event.cc
+++ b/entityx/Event.cc
@@ -12,6 +12,17 @@
namespace entityx {
-BaseEvent::Family BaseEvent::family_counter_ = 0;
+BaseEvent::Family BaseEvent::family_counter_ = 1;
+EventManager::EventManager() {
}
+
+EventManager::~EventManager() {
+}
+
+void EventManager::emit(const BaseEvent &event) {
+ auto sig = signal_for(event.my_family());
+ sig->emit(&event);
+}
+
+} // namespace entityx
diff --git a/entityx/Event.h b/entityx/Event.h
index e6f8fbe..c375aa1 100644
--- a/entityx/Event.h
+++ b/entityx/Event.h
@@ -27,19 +27,20 @@ namespace entityx {
/// Used internally by the EventManager.
class BaseEvent {
public:
- typedef entityx::shared_ptr<BaseEvent> Ptr;
typedef uint64_t Family;
virtual ~BaseEvent() {}
+ virtual Family my_family() const = 0;
+
protected:
static Family family_counter_;
};
typedef Simple::Signal<void (const BaseEvent*)> EventSignal;
-typedef entityx::shared_ptr<EventSignal> EventSignalPtr;
-typedef entityx::weak_ptr<EventSignal> EventSignalWeakPtr;
+typedef ptr<EventSignal> EventSignalPtr;
+typedef weak_ptr<EventSignal> EventSignalWeakPtr;
/**
@@ -53,13 +54,13 @@ typedef entityx::weak_ptr<EventSignal> EventSignalWeakPtr;
template <typename Derived>
class Event : public BaseEvent {
public:
- typedef entityx::shared_ptr<Event<Derived>> Ptr;
-
/// Used internally for registration.
static Family family() {
static Family family = family_counter_++;
return family;
}
+
+ virtual Family my_family() const override { return Derived::family(); }
};
@@ -103,10 +104,13 @@ class Receiver : public BaseReceiver {
*
* Subscriptions are automatically removed when receivers are destroyed..
*/
-class EventManager : public entityx::enable_shared_from_this<EventManager>, boost::noncopyable {
+class EventManager : boost::noncopyable {
public:
- static entityx::shared_ptr<EventManager> make() {
- return entityx::shared_ptr<EventManager>(new EventManager());
+ EventManager();
+ virtual ~EventManager();
+
+ static ptr<EventManager> make() {
+ return ptr<EventManager>(new EventManager());
}
/**
@@ -116,13 +120,13 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
*
* eg.
*
- * struct ExplosionReceiver : public Receiver<ExplosionReceiver> {
- * void receive(const Explosion &explosion) {
- * }
- * };
+ * struct ExplosionReceiver : public Receiver<ExplosionReceiver> {
+ * void receive(const Explosion &explosion) {
+ * }
+ * };
*
- * ExplosionReceiver receiver;
- * em.subscribe<Explosion>(receiver);
+ * ExplosionReceiver receiver;
+ * em.subscribe<Explosion>(receiver);
*/
template <typename E, typename Receiver>
void subscribe(Receiver &receiver) { //NOLINT
@@ -134,6 +138,17 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
std::make_pair(EventSignalWeakPtr(sig), connection));
}
+ void emit(const BaseEvent &event);
+
+ /**
+ * Emit an already constructed event.
+ */
+ template <typename E>
+ void emit(ptr<E> event) {
+ auto sig = signal_for(E::family());
+ sig->emit(static_cast<BaseEvent*>(event.get()));
+ }
+
/**
* Emit an event to receivers.
*
@@ -141,7 +156,7 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
*
* eg.
*
- * entityx::shared_ptr<EventManager> em(entityx::make_shared<EventManager>());
+ * ptr<EventManager> em = new EventManager();
* em->emit<Explosion>(10);
*
*/
@@ -161,12 +176,10 @@ class EventManager : public entityx::enable_shared_from_this<EventManager>, boos
}
private:
- EventManager() {}
-
EventSignalPtr signal_for(int id) {
auto it = handlers_.find(id);
if (it == handlers_.end()) {
- EventSignalPtr sig(entityx::make_shared<EventSignal>());
+ EventSignalPtr sig(new EventSignal());
handlers_.insert(std::make_pair(id, sig));
return sig;
}
diff --git a/entityx/Event_test.cc b/entityx/Event_test.cc
index 2e6528c..7986526 100644
--- a/entityx/Event_test.cc
+++ b/entityx/Event_test.cc
@@ -42,6 +42,17 @@ TEST(EventManagerTest, TestEmitReceive) {
}
+TEST(EventManagerTest, TestUntypedEmitReceive) {
+ auto em = EventManager::make();
+ ExplosionSystem explosion_system;
+ em->subscribe<Explosion>(explosion_system);
+ ASSERT_EQ(0, explosion_system.damage_received);
+ Explosion explosion(10);
+ em->emit(explosion);
+ ASSERT_EQ(10, explosion_system.damage_received);
+}
+
+
TEST(EventManagerTest, TestReceiverExpired) {
auto em = EventManager::make();
{
diff --git a/entityx/Manager.h b/entityx/Manager.h
index 93de090..5151df5 100644
--- a/entityx/Manager.h
+++ b/entityx/Manager.h
@@ -19,10 +19,6 @@ namespace entityx {
class Manager {
public:
- Manager() :
- event_manager(EventManager::make()),
- entity_manager(EntityManager::make(event_manager)),
- system_manager(SystemManager::make(entity_manager, event_manager)) {}
virtual ~Manager() {}
void start();
@@ -30,6 +26,11 @@ class Manager {
void stop();
protected:
+ Manager() :
+ event_manager(EventManager::make()),
+ entity_manager(EntityManager::make(event_manager)),
+ system_manager(SystemManager::make(entity_manager, event_manager)) {}
+
/**
* Configure the world.
*
@@ -52,13 +53,13 @@ class Manager {
*/
virtual void update(double dt) = 0;
- entityx::shared_ptr<EventManager> event_manager;
- entityx::shared_ptr<EntityManager> entity_manager;
- entityx::shared_ptr<SystemManager> system_manager;
+ ptr<EventManager> event_manager;
+ ptr<EntityManager> entity_manager;
+ ptr<SystemManager> system_manager;
private:
boost::timer timer_;
bool running_ = false;
};
-}
+} // namespace entityx
diff --git a/entityx/ReferenceCounted.h b/entityx/ReferenceCounted.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/entityx/ReferenceCounted.h
diff --git a/entityx/System.h b/entityx/System.h
index 473fd55..e4dcfec 100644
--- a/entityx/System.h
+++ b/entityx/System.h
@@ -11,10 +11,10 @@
#pragma once
-#include <stdint.h>
-#include <cassert>
#include <boost/noncopyable.hpp>
#include <boost/unordered_map.hpp>
+#include <stdint.h>
+#include <cassert>
#include "entityx/config.h"
#include "entityx/Entity.h"
#include "entityx/Event.h"
@@ -36,14 +36,14 @@ class BaseSystem : boost::noncopyable {
*
* Typically used to set up event handlers.
*/
- virtual void configure(entityx::shared_ptr<EventManager> events) {}
+ virtual void configure(ptr<EventManager> events) {}
/**
* Apply System behavior.
*
* Called every game step.
*/
- virtual void update(entityx::shared_ptr<EntityManager> entities, entityx::shared_ptr<EventManager> events, double dt) = 0;
+ virtual void update(ptr<EntityManager> entities, ptr<EventManager> events, double dt) = 0;
static Family family_counter_;
@@ -55,7 +55,7 @@ class BaseSystem : boost::noncopyable {
* Use this class when implementing Systems.
*
* struct MovementSystem : public System<MovementSystem> {
- * void update(entityx::shared_ptr<EntityManager> entities, EventManager &events, double dt) {
+ * void update(ptr<EntityManager> entities, EventManager &events, double dt) {
* // Do stuff to/with entities...
* }
* }
@@ -72,11 +72,16 @@ class System : public BaseSystem {
};
-class SystemManager : public entityx::enable_shared_from_this<SystemManager>, boost::noncopyable {
+class SystemManager : boost::noncopyable, public enable_shared_from_this<SystemManager> {
public:
- static entityx::shared_ptr<SystemManager> make(entityx::shared_ptr<EntityManager> entity_manager,
- entityx::shared_ptr<EventManager> event_manager) {
- return entityx::shared_ptr<SystemManager>(new SystemManager(entity_manager, event_manager));
+ SystemManager(ptr<EntityManager> entity_manager,
+ ptr<EventManager> event_manager) :
+ entity_manager_(entity_manager),
+ event_manager_(event_manager) {}
+
+ static ptr<SystemManager> make(ptr<EntityManager> entity_manager,
+ ptr<EventManager> event_manager) {
+ return ptr<SystemManager>(new SystemManager(entity_manager, event_manager));
}
/**
@@ -85,11 +90,11 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
* Must be called before Systems can be used.
*
* eg.
- * entityx::shared_ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
+ * ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
* system.add(movement);
*/
template <typename S>
- void add(entityx::shared_ptr<S> system) {
+ void add(ptr<S> system) {
systems_.insert(std::make_pair(S::family(), system));
}
@@ -102,8 +107,8 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
* auto movement = system.add<MovementSystem>();
*/
template <typename S, typename ... Args>
- entityx::shared_ptr<S> add(Args && ... args) {
- entityx::shared_ptr<S> s = entityx::make_shared<S>(args ...);
+ ptr<S> add(Args && ... args) {
+ ptr<S> s(new S(args ...));
add(s);
return s;
}
@@ -111,17 +116,17 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
/**
* Retrieve the registered System instance, if any.
*
- * entityx::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
+ * ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
*
* @return System instance or empty shared_ptr<S>.
*/
template <typename S>
- entityx::shared_ptr<S> system() {
+ ptr<S> system() {
auto it = systems_.find(S::family());
assert(it != systems_.end());
return it == systems_.end()
- ? entityx::shared_ptr<S>()
- : entityx::static_pointer_cast<S>(it->second);
+ ? ptr<S>()
+ : ptr<S>(static_pointer_cast<S>(it->second));
}
/**
@@ -130,7 +135,7 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
template <typename S>
void update(double dt) {
assert(initialized_ && "SystemManager::configure() not called");
- entityx::shared_ptr<S> s = system<S>();
+ ptr<S> s = system<S>();
s->update(entity_manager_, event_manager_, dt);
}
@@ -142,15 +147,10 @@ class SystemManager : public entityx::enable_shared_from_this<SystemManager>, bo
void configure();
private:
- SystemManager(entityx::shared_ptr<EntityManager> entity_manager,
- entityx::shared_ptr<EventManager> event_manager) :
- entity_manager_(entity_manager),
- event_manager_(event_manager) {}
-
bool initialized_ = false;
- entityx::shared_ptr<EntityManager> entity_manager_;
- entityx::shared_ptr<EventManager> event_manager_;
- boost::unordered_map<BaseSystem::Family, entityx::shared_ptr<BaseSystem>> systems_;
+ ptr<EntityManager> entity_manager_;
+ ptr<EventManager> event_manager_;
+ boost::unordered_map<BaseSystem::Family, ptr<BaseSystem>> systems_;
};
-}
+} // namespace entityx
diff --git a/entityx/System_test.cc b/entityx/System_test.cc
index a68a032..0d82df5 100644
--- a/entityx/System_test.cc
+++ b/entityx/System_test.cc
@@ -35,12 +35,12 @@ struct Direction : Component<Direction> {
class MovementSystem : public System<MovementSystem> {
public:
- MovementSystem(string label = "") : label(label) {}
+ explicit MovementSystem(string label = "") : label(label) {}
- void update(entityx::shared_ptr<EntityManager> es, entityx::shared_ptr<EventManager> events, double) override {
+ void update(ptr<EntityManager> es, ptr<EventManager> events, double) override {
EntityManager::View entities = es->entities_with_components<Position, Direction>();
- entityx::shared_ptr<Position> position;
- entityx::shared_ptr<Direction> direction;
+ ptr<Position> position;
+ ptr<Direction> direction;
for (auto entity : entities) {
entity.unpack<Position, Direction>(position, direction);
position->x += direction->x;
@@ -56,8 +56,8 @@ class TestManager : public entityx::Manager {
public:
std::vector<Entity> entities;
- entityx::shared_ptr<SystemManager> sm() { return system_manager; }
- entityx::shared_ptr<EntityManager> em() { return entity_manager; }
+ ptr<SystemManager> sm() { return system_manager; }
+ ptr<EntityManager> em() { return entity_manager; }
protected:
void configure() override {
@@ -102,8 +102,8 @@ TEST_F(SystemManagerTest, TestApplySystem) {
manager.sm()->configure();
manager.sm()->update<MovementSystem>(0.0);
- entityx::shared_ptr<Position> position;
- entityx::shared_ptr<Direction> direction;
+ ptr<Position> position;
+ ptr<Direction> direction;
for (auto entity : manager.entities) {
entity.unpack<Position, Direction>(position, direction);
if (position && direction) {
diff --git a/entityx/config.h.in b/entityx/config.h.in
index 9722cf4..de43e83 100644
--- a/entityx/config.h.in
+++ b/entityx/config.h.in
@@ -9,6 +9,14 @@
#cmakedefine ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION "@ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION@"
#include <stdint.h>
+#include "entityx/config.h"
+
+namespace entityx {
+
+static const uint64_t MAX_COMPONENTS = ENTITYX_MAX_COMPONENTS;
+
+} // namespace entityx
+
// Which shared_ptr implementation should we use?
#if (ENTITYX_HAVE_STD_SHARED_PTR && ENTITYX_USE_STD_SHARED_PTR)
@@ -16,30 +24,59 @@
#include <memory>
namespace entityx {
-using std::make_shared;
-using std::shared_ptr;
-using std::static_pointer_cast;
-using std::weak_ptr;
-using std::enable_shared_from_this;
+
+template <typename T>
+using ptr = std::shared_ptr<T>;
+template <typename T>
+using weak_ptr = std::weak_ptr<T>;
+template <typename T, typename U>
+ptr<U> static_pointer_cast(const ptr<T> &ptr) {
+ return std::static_pointer_cast<U>(ptr);
}
+template <typename T>
+using enable_shared_from_this = std::enable_shared_from_this<T>;
+
+} // namespace entityx
#elif ENTITYX_HAVE_BOOST_SHARED_PTR
-#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
-#include <boost/make_shared.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
namespace entityx {
-using boost::shared_ptr;
-using boost::make_shared;
-using boost::static_pointer_cast;
-using boost::weak_ptr;
-using boost::enable_shared_from_this;
+
+template <typename T>
+using ptr = boost::shared_ptr<T>;
+template <typename T>
+using weak_ptr = boost::weak_ptr<T>;
+template <typename T, typename U>
+ptr<U> static_pointer_cast(const ptr<T> &ptr) {
+ return boost::static_pointer_cast<U>(ptr);
}
+template <typename T>
+using enable_shared_from_this = boost::enable_shared_from_this<T>;
+
+} // namespace entityx
+
+#else
+
+#warning "Don't have a boost or std shared_ptr implementation to use"
#endif
+
namespace entityx {
-static const uint64_t MAX_COMPONENTS = ENTITYX_MAX_COMPONENTS;
+
+template <typename T>
+bool operator == (const weak_ptr<T> &a, const weak_ptr<T> &b) {
+ return a.lock() == b.lock();
}
+
+template <typename T>
+int use_count(const ptr<T> &ptr) {
+ return ptr.use_count();
+}
+
+} // namespace entityx
diff --git a/entityx/python/PythonSystem.cc b/entityx/python/PythonSystem.cc
index 0abdde6..bb59e7d 100644
--- a/entityx/python/PythonSystem.cc
+++ b/entityx/python/PythonSystem.cc
@@ -16,8 +16,6 @@
#include <sstream>
#include "entityx/python/PythonSystem.h"
-using namespace std;
-using namespace boost;
namespace py = boost::python;
namespace entityx {
@@ -41,31 +39,56 @@ class PythonEntityXLogger {
public:
PythonEntityXLogger() {}
explicit PythonEntityXLogger(PythonSystem::LoggerFunction logger) : logger_(logger) {}
+ ~PythonEntityXLogger() { flush(true); }
void write(const std::string &text) {
- logger_(text);
+ line_ += text;
+ flush();
}
+
private:
+ void flush(bool force = false) {
+ size_t offset;
+ while ((offset = line_.find('\n')) != std::string::npos) {
+ std::string text = line_.substr(0, offset);
+ logger_(text);
+ line_ = line_.substr(offset + 1);
+ }
+ if (force && line_.size()) {
+ logger_(line_);
+ line_ = "";
+ }
+ }
+
PythonSystem::LoggerFunction logger_;
+ std::string line_;
};
struct PythonEntity {
- explicit PythonEntity(Entity entity) : _entity(entity) {}
+ PythonEntity(Entity entity) : _entity(entity) {} // NOLINT
void destroy() {
_entity.destroy();
}
- void update(float dt) {}
+ operator Entity () const { return _entity; }
+
+ void update(float dt, int frame) {}
Entity _entity;
};
+static std::string python_entity_repr(const PythonEntity &entity) {
+ std::stringstream repr;
+ repr << "<Entity " << entity._entity.id().index() << "." << entity._entity.id().version() << ">";
+ return repr.str();
+}
+
static std::string entity_repr(Entity entity) {
- stringstream repr;
- repr << "<Entity::Id " << entity.id() << ">";
+ std::stringstream repr;
+ repr << "<Entity::Id " << entity.id().index() << "." << entity.id().version() << ">";
return repr.str();
}
@@ -80,39 +103,49 @@ BOOST_PYTHON_MODULE(_entityx) {
py::class_<PythonEntityXLogger>("Logger", py::no_init)
.def("write", &PythonEntityXLogger::write);
+ py::class_<BaseEvent, ptr<BaseEvent>, boost::noncopyable>("BaseEvent", py::no_init);
+
py::class_<PythonEntity>("Entity", py::init<Entity>())
.def_readonly("_entity", &PythonEntity::_entity)
.def("update", &PythonEntity::update)
- .def("destroy", &PythonEntity::destroy);
+ .def("destroy", &PythonEntity::destroy)
+ .def("__repr__", &python_entity_repr);
py::class_<Entity>("RawEntity", py::no_init)
.add_property("id", &Entity::id)
.def("__eq__", &entity_eq)
.def("__repr__", &entity_repr);
- py::class_<PythonComponent, entityx::shared_ptr<PythonComponent>>("PythonComponent", py::init<py::object>())
+ py::class_<PythonComponent, ptr<PythonComponent>>("PythonComponent", py::init<py::object>())
.def("assign_to", &assign_to<PythonComponent>)
.def("get_component", &get_component<PythonComponent>)
.staticmethod("get_component");
- py::class_<EntityManager, entityx::shared_ptr<EntityManager>, boost::noncopyable>("EntityManager", py::no_init)
+ py::class_<EntityManager, ptr<EntityManager>, boost::noncopyable>("EntityManager", py::no_init)
.def("create", &EntityManager::create);
+
+ void (EventManager::*emit)(const BaseEvent &) = &EventManager::emit;
+
+ py::class_<EventManager, ptr<EventManager>, boost::noncopyable>("EventManager", py::no_init)
+ .def("emit", emit);
+
+ py::implicitly_convertible<PythonEntity, Entity>();
}
static void log_to_stderr(const std::string &text) {
- cerr << "python stderr: " << text << endl;
+ std::cerr << "python stderr: " << text << std::endl;
}
static void log_to_stdout(const std::string &text) {
- cout << "python stdout: " << text << endl;
+ std::cout << "python stdout: " << text << std::endl;
}
// PythonSystem below here
bool PythonSystem::initialized_ = false;
-PythonSystem::PythonSystem(entityx::shared_ptr<EntityManager> entity_manager)
+PythonSystem::PythonSystem(ptr<EntityManager> entity_manager)
: entity_manager_(entity_manager), stdout_(log_to_stdout), stderr_(log_to_stderr) {
if (!initialized_) {
initialize_python_module();
@@ -125,6 +158,20 @@ PythonSystem::PythonSystem(entityx::shared_ptr<EntityManager> entity_manager)
}
PythonSystem::~PythonSystem() {
+ try {
+ py::object entityx = py::import("_entityx");
+ entityx.attr("_entity_manager").del();
+ entityx.attr("_event_manager").del();
+ py::object sys = py::import("sys");
+ sys.attr("stdout").del();
+ sys.attr("stderr").del();
+ py::object gc = py::import("gc");
+ gc.attr("collect")();
+ } catch(...) {
+ PyErr_Print();
+ PyErr_Clear();
+ throw;
+ }
// FIXME: It would be good to do this, but it is not supported by boost::python:
// http://www.boost.org/doc/libs/1_53_0/libs/python/todo.html#pyfinalize-safety
// Py_Finalize();
@@ -142,7 +189,7 @@ void PythonSystem::initialize_python_module() {
assert(PyImport_AppendInittab("_entityx", init_entityx) != -1 && "Failed to initialize _entityx Python module");
}
-void PythonSystem::configure(entityx::shared_ptr<EventManager> event_manager) {
+void PythonSystem::configure(ptr<EventManager> event_manager) {
event_manager->subscribe<EntityDestroyedEvent>(*this);
event_manager->subscribe<ComponentAddedEvent<PythonComponent>>(*this);
@@ -162,8 +209,8 @@ void PythonSystem::configure(entityx::shared_ptr<EventManager> event_manager) {
}
py::object entityx = py::import("_entityx");
- entityx.attr("_entity_manager") = entity_manager_;
- // entityx.attr("event_manager") = boost::ref(event_manager);
+ entityx.attr("_entity_manager") = entity_manager_.lock();
+ entityx.attr("_event_manager") = event_manager;
} catch(...) {
PyErr_Print();
PyErr_Clear();
@@ -171,18 +218,19 @@ void PythonSystem::configure(entityx::shared_ptr<EventManager> event_manager) {
}
}
-void PythonSystem::update(entityx::shared_ptr<EntityManager> entity_manager, entityx::shared_ptr<EventManager> event_manager, double dt) {
+void PythonSystem::update(ptr<EntityManager> entity_manager, ptr<EventManager> event_manager, double dt) {
for (auto entity : entity_manager->entities_with_components<PythonComponent>()) {
- shared_ptr<PythonComponent> python = entity.component<PythonComponent>();
+ ptr<PythonComponent> python = entity.component<PythonComponent>();
try {
- python->object.attr("update")(dt);
+ python->object.attr("update")(dt, frame_);
} catch(...) {
PyErr_Print();
PyErr_Clear();
throw;
}
}
+ frame_++;
}
void PythonSystem::log_to(LoggerFunction stdout, LoggerFunction stderr) {
diff --git a/entityx/python/PythonSystem.h b/entityx/python/PythonSystem.h
index b64e46c..3009c6c 100644
--- a/entityx/python/PythonSystem.h
+++ b/entityx/python/PythonSystem.h
@@ -12,16 +12,21 @@
// http://docs.python.org/2/extending/extending.html
#include <Python.h>
-
+#include <boost/python.hpp>
+#include <boost/function.hpp>
+#include <list>
+#include <vector>
+#include <string>
+#include "entityx/System.h"
+#include "entityx/Entity.h"
+#include "entityx/Event.h"
#include "entityx/config.h"
// boost::python smart pointer adapter for std::shared_ptr<T>
-#if (ENTITYX_HAVE_STD_SHARED_PTR && ENTITYX_USE_STD_SHARED_PTR)
+#ifdef ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION
-#include <boost/python.hpp>
#include <memory>
-#ifdef ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION
namespace std {
@@ -30,46 +35,25 @@ template <class T> inline T * get_pointer(const std::shared_ptr<T> &p) {
return p.get();
}
-}
+} // namespace std
-#endif
-
-namespace boost {
-namespace python {
-
-template <typename T> struct pointee<std::shared_ptr<T> > {
- typedef T type;
-};
-
-}
-}
#endif
-#include <list>
-#include <vector>
-#include <string>
-#include <boost/python.hpp>
-#include <boost/function.hpp>
-#include "entityx/System.h"
-#include "entityx/Entity.h"
-#include "entityx/Event.h"
-
namespace entityx {
namespace python {
-
/**
* An EntityX component that represents a Python script.
*/
class PythonComponent : public entityx::Component<PythonComponent> {
public:
/**
- * Create a new PythonComponent from a Python class.
+ * Create a new PythonComponent from a Python Entity class.
*
* @param module The Python module where the Entity subclass resides.
- * @param cls The Class within the module.
+ * @param cls The Class within the module. Must inherit from entityx.Entity.
* @param args The *args to pass to the Python constructor.
*/
template <typename ...Args>
@@ -160,7 +144,7 @@ private:
* A helper function for class_ to assign a component to an entity.
*/
template <typename Component>
-void assign_to(entityx::shared_ptr<Component> component, Entity &entity) { // NOLINT
+void assign_to(ptr<Component> component, Entity &entity) { // NOLINT
entity.assign<Component>(component);
}
@@ -170,7 +154,7 @@ void assign_to(entityx::shared_ptr<Component> component, Entity &entity) { // N
* entity.
*/
template <typename Component>
-entityx::shared_ptr<Component> get_component(Entity &entity) { // NOLINT
+ptr<Component> get_component(Entity &entity) { // NOLINT
return entity.component<Component>();
}
@@ -206,7 +190,7 @@ class PythonSystem : public entityx::System<PythonSystem>, public entityx::Recei
public:
typedef boost::function<void (const std::string &)> LoggerFunction;
- PythonSystem(entityx::shared_ptr<EntityManager> entity_manager); // NOLINT
+ PythonSystem(ptr<EntityManager> entity_manager); // NOLINT
virtual ~PythonSystem();
/**
@@ -234,11 +218,11 @@ public:
return python_paths_;
}
- virtual void configure(entityx::shared_ptr<EventManager> event_manager) override;
- virtual void update(entityx::shared_ptr<EntityManager> entities, entityx::shared_ptr<EventManager> event_manager, double dt) override;
+ virtual void configure(ptr<EventManager> event_manager) override;
+ virtual void update(ptr<EntityManager> entities, ptr<EventManager> event_manager, double dt) override;
/**
- * Set functions that writes to sys.stdout/sys.stderr will be passed to.
+ * Set line-based (not including \n) logger for stdout and stderr.
*/
void log_to(LoggerFunction stdout, LoggerFunction stderr);
@@ -246,32 +230,34 @@ public:
* Proxy events of type Event to any Python entity with a handler_name method.
*/
template <typename Event>
- void add_event_proxy(entityx::shared_ptr<EventManager> event_manager, const std::string &handler_name) {
- auto proxy = entityx::make_shared<BroadcastPythonEventProxy<Event>>(handler_name);
- event_manager->subscribe<Event>(*proxy);
- event_proxies_.push_back(entityx::static_pointer_cast<PythonEventProxy>(proxy));
+ void add_event_proxy(ptr<EventManager> event_manager, const std::string &handler_name) {
+ ptr<BroadcastPythonEventProxy<Event>> proxy(new BroadcastPythonEventProxy<Event>(handler_name));
+ event_manager->subscribe<Event>(*proxy.get());
+ event_proxies_.push_back(static_pointer_cast<PythonEventProxy>(proxy));
}
/**
* Proxy events of type Event using the given PythonEventProxy implementation.
*/
template <typename Event, typename Proxy>
- void add_event_proxy(entityx::shared_ptr<EventManager> event_manager, entityx::shared_ptr<Proxy> proxy) {
+ void add_event_proxy(ptr<EventManager> event_manager, ptr<Proxy> proxy) {
event_manager->subscribe<Event>(*proxy);
- event_proxies_.push_back(entityx::static_pointer_cast<PythonEventProxy>(proxy));
+ event_proxies_.push_back(static_pointer_cast<PythonEventProxy>(proxy));
}
void receive(const EntityDestroyedEvent &event);
void receive(const ComponentAddedEvent<PythonComponent> &event);
+
private:
void initialize_python_module();
- entityx::shared_ptr<EntityManager> entity_manager_;
+ weak_ptr<EntityManager> entity_manager_;
std::vector<std::string> python_paths_;
LoggerFunction stdout_, stderr_;
static bool initialized_;
- std::vector<entityx::shared_ptr<PythonEventProxy>> event_proxies_;
+ std::vector<ptr<PythonEventProxy>> event_proxies_;
+ int frame_ = 0;
};
-}
-}
+} // namespace python
+} // namespace entityx
diff --git a/entityx/python/PythonSystem_test.cc b/entityx/python/PythonSystem_test.cc
index f516830..1d0c8fd 100644
--- a/entityx/python/PythonSystem_test.cc
+++ b/entityx/python/PythonSystem_test.cc
@@ -19,8 +19,6 @@
#include "entityx/Event.h"
#include "entityx/python/PythonSystem.h"
-using namespace std;
-using namespace boost;
namespace py = boost::python;
using namespace entityx;
using namespace entityx::python;
@@ -62,19 +60,21 @@ struct CollisionEventProxy : public PythonEventProxy, public Receiver<CollisionE
BOOST_PYTHON_MODULE(entityx_python_test) {
- py::class_<Position, entityx::shared_ptr<Position>>("Position", py::init<py::optional<float, float>>())
+ py::class_<Position, ptr<Position>>("Position", py::init<py::optional<float, float>>())
.def("assign_to", &assign_to<Position>)
.def("get_component", &get_component<Position>)
.staticmethod("get_component")
.def_readwrite("x", &Position::x)
.def_readwrite("y", &Position::y);
- py::class_<Direction, entityx::shared_ptr<Direction>>("Direction", py::init<py::optional<float, float>>())
+
+ py::class_<Direction, ptr<Direction>>("Direction", py::init<py::optional<float, float>>())
.def("assign_to", &assign_to<Direction>)
.def("get_component", &get_component<Direction>)
.staticmethod("get_component")
.def_readwrite("x", &Direction::x)
.def_readwrite("y", &Direction::y);
- py::class_<CollisionEvent>("Collision", py::init<Entity, Entity>())
+
+ py::class_<CollisionEvent, ptr<CollisionEvent>, py::bases<BaseEvent>>("Collision", py::init<Entity, Entity>())
.def_readonly("a", &CollisionEvent::a)
.def_readonly("b", &CollisionEvent::b);
}
@@ -87,29 +87,30 @@ protected:
}
void SetUp() {
- ev = EventManager::make();
- em = EntityManager::make(ev);
- vector<string> paths;
- paths.push_back(ENTITYX_PYTHON_TEST_DATA);
- system = entityx::make_shared<PythonSystem>(em);
- system->add_paths(paths);
+ ev.reset(new EventManager());
+ em.reset(new EntityManager(ev));
+ system.reset(new PythonSystem(em));
+ system->add_path(ENTITYX_PYTHON_TEST_DATA);
if (!initialized) {
initentityx_python_test();
initialized = true;
}
- system->add_event_proxy<CollisionEvent>(ev, entityx::make_shared<CollisionEventProxy>());
+ system->add_event_proxy<CollisionEvent, CollisionEventProxy>(ev, ptr<CollisionEventProxy>(new CollisionEventProxy()));
system->configure(ev);
}
void TearDown() {
+ weak_ptr<EventManager> v = ev;
+ weak_ptr<EntityManager> e = em;
+ em->destroy_all();
system.reset();
em.reset();
ev.reset();
}
- entityx::shared_ptr<PythonSystem> system;
- entityx::shared_ptr<EventManager> ev;
- entityx::shared_ptr<EntityManager> em;
+ ptr<PythonSystem> system;
+ ptr<EventManager> ev;
+ ptr<EntityManager> em;
static bool initialized;
};
@@ -123,7 +124,7 @@ TEST_F(PythonSystemTest, TestSystemUpdateCallsEntityUpdate) {
ASSERT_FALSE(py::extract<bool>(script->object.attr("updated")));
system->update(em, ev, 0.1);
ASSERT_TRUE(py::extract<bool>(script->object.attr("updated")));
- } catch (...) {
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
@@ -135,15 +136,15 @@ TEST_F(PythonSystemTest, TestComponentAssignmentCreationInPython) {
try {
Entity e = em->create();
auto script = e.assign<PythonComponent>("entityx.tests.assign_test", "AssignTest");
- ASSERT_TRUE(bool(e.component<Position>()));
+ ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
ASSERT_TRUE(script->object);
ASSERT_TRUE(script->object.attr("test_assign_create"));
script->object.attr("test_assign_create")();
auto position = e.component<Position>();
- ASSERT_TRUE(bool(position));
+ ASSERT_TRUE(static_cast<bool>(position));
ASSERT_EQ(position->x, 1.0);
ASSERT_EQ(position->y, 2.0);
- } catch (...) {
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
@@ -156,15 +157,15 @@ TEST_F(PythonSystemTest, TestComponentAssignmentCreationInCpp) {
Entity e = em->create();
e.assign<Position>(2, 3);
auto script = e.assign<PythonComponent>("entityx.tests.assign_test", "AssignTest");
- ASSERT_TRUE(bool(e.component<Position>()));
+ ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
ASSERT_TRUE(script->object);
ASSERT_TRUE(script->object.attr("test_assign_existing"));
script->object.attr("test_assign_existing")();
auto position = e.component<Position>();
- ASSERT_TRUE(bool(position));
+ ASSERT_TRUE(static_cast<bool>(position));
ASSERT_EQ(position->x, 3.0);
ASSERT_EQ(position->y, 4.0);
- } catch (...) {
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
@@ -177,10 +178,10 @@ TEST_F(PythonSystemTest, TestEntityConstructorArgs) {
Entity e = em->create();
auto script = e.assign<PythonComponent>("entityx.tests.constructor_test", "ConstructorTest", 4.0, 5.0);
auto position = e.component<Position>();
- ASSERT_TRUE(bool(position));
+ ASSERT_TRUE(static_cast<bool>(position));
ASSERT_EQ(position->x, 4.0);
ASSERT_EQ(position->y, 5.0);
- } catch (...) {
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
@@ -203,7 +204,7 @@ TEST_F(PythonSystemTest, TestEventDelivery) {
ev->emit<CollisionEvent>(e, f);
ASSERT_TRUE(scriptf->object.attr("collided"));
ASSERT_TRUE(scripte->object.attr("collided"));
- } catch (...) {
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
@@ -222,7 +223,7 @@ TEST_F(PythonSystemTest, TestDeepEntitySubclass) {
auto script2 = e2.assign<PythonComponent>("entityx.tests.deep_subclass_test", "DeepSubclassTest2");
ASSERT_TRUE(script2->object.attr("test_deeper_subclass"));
script2->object.attr("test_deeper_subclass")();
- } catch (...) {
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
@@ -234,7 +235,37 @@ TEST_F(PythonSystemTest, TestEntityCreationFromPython) {
try {
py::object test = py::import("entityx.tests.create_entities_from_python_test");
test.attr("create_entities_from_python_test")();
- } catch (...) {
+ } catch(...) {
+ PyErr_Print();
+ PyErr_Clear();
+ ASSERT_FALSE(true) << "Python exception.";
+ }
+}
+
+
+TEST_F(PythonSystemTest, TestEventEmissionFromPython) {
+ try {
+ struct CollisionReceiver : public Receiver<CollisionReceiver> {
+ void receive(const CollisionEvent &event) {
+ a = event.a;
+ b = event.b;
+ }
+
+ Entity a, b;
+ };
+
+ CollisionReceiver receiver;
+ ev->subscribe<CollisionEvent>(receiver);
+
+ ASSERT_FALSE(receiver.a);
+ ASSERT_FALSE(receiver.b);
+
+ py::object test = py::import("entityx.tests.event_emit_test");
+ test.attr("emit_collision_from_python")();
+
+ ASSERT_TRUE(receiver.a);
+ ASSERT_TRUE(receiver.b);
+ } catch(...) {
PyErr_Print();
PyErr_Clear();
ASSERT_FALSE(true) << "Python exception.";
diff --git a/entityx/python/README.md b/entityx/python/README.md
index 9b06903..e206a05 100644
--- a/entityx/python/README.md
+++ b/entityx/python/README.md
@@ -28,6 +28,7 @@ To add scripting support to your system, something like the following steps shou
5. Create a `PythonSystem`, passing in the list of paths to add to Python's import search path.
6. Optionally attach any event proxies.
7. Create an entity and associate it with a Python script by assigning `PythonComponent`, passing it the package name, class name, and any constructor arguments.
+8. When finished, call `EntityManager::destroy_all()`.
## Interfacing with Python
@@ -49,7 +50,7 @@ struct Position : public Component<Position> {
};
void export_position_to_python() {
- py::class_<PythonPosition, entityx::shared_ptr<PythonPosition>>("Position", py::init<py::optional<float, float>>())
+ py::class_<PythonPosition, entityx::ptr<PythonPosition>>("Position", py::init<py::optional<float, float>>())
.def("assign_to", &entityx::python::assign_to<Position>)
.def("get_component", &entityx::python::get_component<Position>)
.staticmethod("get_component")
@@ -137,9 +138,8 @@ Then create and destroy `PythonSystem` as necessary:
vector<string> paths;
paths.push_back(MYGAME_PYTHON_PATH);
// +any other Python paths...
-auto script_system = make_shared<PythonSystem>(paths);
+entityx::ptr<PythonSystem> script_system = new PythonSystem(paths);
// Add any Event proxies.
-script_system->add_event_proxy<CollisionEvent>(
- ev, entityx::make_shared<CollisionEventProxy>());
+script_system->add_event_proxy<CollisionEvent>(ev, new CollisionEventProxy());
```
diff --git a/entityx/python/entityx/__init__.py b/entityx/python/entityx/__init__.py
index cdac6a6..8f5057b 100644
--- a/entityx/python/entityx/__init__.py
+++ b/entityx/python/entityx/__init__.py
@@ -11,7 +11,7 @@ They allow you to declare your entities and components in an intuitive way:
direction = Component(Direction)
sprite = Component(Sprite, 'player.png') # Sprite component with constructor argument
- def update(self, dt):
+ def update(self, dt, frame):
self.position.x += self.direction.x * dt
self.position.x += self.direction.y * dt
@@ -100,3 +100,11 @@ class Entity(_entityx.Entity):
self = Entity.__new__(cls, raw_entity=raw_entity)
cls.__init__(self, *args, **kwargs)
return self
+
+
+def emit(event):
+ """Emit an event.
+
+ :param event: A Python-exposed C++ subclass of entityx::BaseEvent.
+ """
+ return _entityx._event_manager.emit(event)
diff --git a/entityx/python/entityx/tests/event_emit_test.py b/entityx/python/entityx/tests/event_emit_test.py
new file mode 100644
index 0000000..9a726ba
--- /dev/null
+++ b/entityx/python/entityx/tests/event_emit_test.py
@@ -0,0 +1,14 @@
+from entityx import Entity, emit
+from entityx_python_test import Collision
+
+
+class AnEntity(Entity):
+ pass
+
+
+def emit_collision_from_python():
+ a = AnEntity()
+ b = AnEntity()
+ collision = Collision(a, b)
+ print a, b, collision
+ emit(Collision(a, b))
diff --git a/entityx/python/entityx/tests/update_test.py b/entityx/python/entityx/tests/update_test.py
index 3c05d6a..7585aa6 100644
--- a/entityx/python/entityx/tests/update_test.py
+++ b/entityx/python/entityx/tests/update_test.py
@@ -4,5 +4,5 @@ import entityx
class UpdateTest(entityx.Entity):
updated = False
- def update(self, dt):
+ def update(self, dt, frame):
self.updated = True
diff --git a/entityx/tags/TagsComponent.h b/entityx/tags/TagsComponent.h
index 6598f61..b208c63 100644
--- a/entityx/tags/TagsComponent.h
+++ b/entityx/tags/TagsComponent.h
@@ -10,8 +10,8 @@
#pragma once
-#include <string>
#include <boost/unordered_set.hpp>
+#include <string>
#include "entityx/Entity.h"
namespace entityx {
@@ -22,11 +22,11 @@ namespace tags {
*/
class TagsComponent : public Component<TagsComponent> {
struct TagsPredicate {
- TagsPredicate(const std::string &tag) : tag(tag) {}
+ explicit TagsPredicate(const std::string &tag) : tag(tag) {}
- bool operator () (entityx::shared_ptr<EntityManager> manager, Entity::Id id) {
+ bool operator() (ptr<EntityManager> manager, Entity::Id id) {
auto tags = manager->component<TagsComponent>(id);
- return tags != nullptr && tags->tags.find(tag) != tags->tags.end();
+ return tags && tags->tags.find(tag) != tags->tags.end();
}
std::string tag;
@@ -64,5 +64,5 @@ class TagsComponent : public Component<TagsComponent> {
}
};
-}
-}
+} // namespace tags
+} // namespace entityx