Fixes #6.
*.so
*.o
build/*
+entityx/config.h
compiler:
- clang
- gcc
+env:
+ - USE_STD_SHARED_PTR=1
+ - USE_STD_SHARED_PTR=0
before_install:
- sudo apt-add-repository -y ppa:jkeiren/ppa
- if test $CC = gcc; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
- if test $CC = gcc; then sudo update-alternatives --config gcc; fi
- if test $CC = gcc; then sudo update-alternatives --config g++; fi
-script: cmake -DBUILD_TESTING=1 && make && make test
+script: ./scripts/travis.sh
set(RUN_BENCHMARKS false CACHE BOOL "Run benchmarks")
include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
+include(CheckCXXSourceCompiles)
+
+# Default compiler args
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Werror -Wall -Wextra -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=sign-compare -std=c++11")
+set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
+set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
+
# C++11 feature checks
include(CheckCXX11Features.cmake)
+
# Misc features
-CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
+check_include_file("stdint.h" HAVE_STDINT_H)
+
+set(USE_CPP11_STDLIB false CACHE BOOL "Use the C++11 stdlib (-stdlib=libc++).")
+
+if (USE_CPP11_STDLIB)
+ set(OLD_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ check_cxx_source_compiles(
+ "
+ #include <memory>
+
+ int main() {
+ std::shared_ptr<int>();
+ }
+ "
+ HAVE_CXX11_STDLIB
+ )
+
+ if (NOT HAVE_CXX11_STDLIB)
+ message("-- Not using -stdlib=libc++ (test failed to build)")
+ set(CMAKE_CXX_FLAGS "${OLD_CMAKE_CXX_FLAGS}")
+ else ()
+ message("-- Using -stdlib=libc++")
+ endif ()
+else ()
+ message("-- Using default stdlib (try -DUSE_CPP11_STDLIB=1 to use -stdlib=libc++)")
+endif ()
+
+# Check for which shared_ptr implementation to use.
+set(USE_STD_SHARED_PTR false CACHE BOOL "Use std::shared_ptr<T> rather than boost::shared_ptr<T>?")
+
+check_cxx_source_compiles(
+"
+#include <memory>
+
+int main() { std::shared_ptr<int>(); }
+"
+HAVE_STD_SHARED_PTR
+)
+
+check_cxx_source_compiles(
+"
+#include <boost/shared_ptr.hpp>
+
+int main() { boost::shared_ptr<int>(); }
+"
+HAVE_BOOST_SHARED_PTR
+)
+
+if (HAVE_STD_SHARED_PTR AND USE_STD_SHARED_PTR)
+ message("-- Using std::shared_ptr<T>")
+else()
+ if (USE_STD_SHARED_PTR)
+ message("-- Using boost::shared_ptr<T> (std::shared_ptr<T> could not be used)")
+ else()
+ message("-- Using boost::shared_ptr<T> (try -DUSE_STD_SHARED_PTR=1 to use std::shared_ptr<T>)")
+ endif()
+endif()
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/entityx/config.h.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/entityx/config.h
+)
macro(require FEATURE_NAME MESSAGE_STRING)
if (NOT ${${FEATURE_NAME}})
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.48.0 REQUIRED COMPONENTS signals)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Werror -Wall -Wextra -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=sign-compare -std=c++11")
-set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
-set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
-set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
-
set(sources entityx/Components.cc entityx/System.cc entityx/Event.cc entityx/Entity.cc entityx/Manager.cc)
add_library(entityx STATIC ${sources})
add_library(entityx_shared SHARED ${sources})
# EntityX - A fast, type-safe C++ Entity-Component system
+[](https://travis-ci.org/alecthomas/entityx)
+
Entity-Component (EC) systems are a form of decomposition that completely decouples entity logic and data from the entity "objects" themselves. The [Evolve your Hierarchy](http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/) article provides a solid overview of EC systems and why you should use them.
EntityX is an EC system that uses C++11 features to provide type-safe component management, event delivery, etc. It was built during the creation of a 2D space shooter.
You can also assign existing instances of components:
```c++
-boost::shared_ptr<Position> position = boost::make_shared<Position>(1.0f, 2.0f);
+entityx::shared_ptr<Position> position = entityx::make_shared<Position>(1.0f, 2.0f);
entity.assign(position);
```
```c++
for (auto entity : entities.entities_with_components<Position, Direction>()) {
- boost::shared_ptr<Position> position = entity.component<Position>();
- boost::shared_ptr<Direction> direction = entity.component<Direction>();
+ entityx::shared_ptr<Position> position = entity.component<Position>();
+ entityx::shared_ptr<Direction> direction = entity.component<Direction>();
// Do things with entity, position and direction.
}
To retrieve a component associated with an entity use ``Entity::component<C>()``:
```c++
-boost::shared_ptr<Position> position = entity.component<Position>();
+entityx::shared_ptr<Position> position = entity.component<Position>();
if (position) {
// Do stuff with position
}
struct MovementSystem : public System<MovementSystem> {
void update(EntityManager &es, EventManager &events, double dt) override {
for (auto entity : es.entities_with_components<Position, Direction>()) {
- boost::shared_ptr<Position> position = entity.component<Position>();
- boost::shared_ptr<Direction> direction = entity.component<Direction>();
+ entityx::shared_ptr<Position> position = entity.component<Position>();
+ entityx::shared_ptr<Direction> direction = entity.component<Direction>();
position->x += direction->x * dt;
position->y += direction->y * dt;
class CollisionSystem : public System<CollisionSystem> {
public:
void update(EntityManager &es, EventManager &events, double dt) override {
- boost::shared_ptr<Position> left_position, right_position;
+ 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>()) {
if (collide(left_position, right_position)) {
- `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.
- - `boost::shared_ptr<T> component` - The component added.
+ - `entityx::shared_ptr<T> component` - The component added.
#### Implementation notes
for (int i = 0; i < 10; ++i) {
for (auto e : em.entities_with_components<Position>()) {
- boost::shared_ptr<Position> position = e.component<Position>();
+ entityx::shared_ptr<Position> position = e.component<Position>();
}
}
}
/**
* Copyright (C) 2012 Alec Thomas <alec@swapoff.org>
* All rights reserved.
- *
+ *
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution.
- *
+ *
* Author: Alec Thomas <alec@swapoff.org>
*/
#include <utility>
#include <vector>
-#include <boost/shared_ptr.hpp>
+#include "entityx/config.h"
#include "entityx/Event.h"
namespace entityx {
EntityManager &manager() { return *manager_; }
template <typename C>
- boost::shared_ptr<C> assign(boost::shared_ptr<C> component);
+ entityx::shared_ptr<C> assign(entityx::shared_ptr<C> component);
template <typename C, typename ... Args>
- boost::shared_ptr<C> assign(Args && ... args);
+ entityx::shared_ptr<C> assign(Args && ... args);
template <typename C>
- boost::shared_ptr<C> component();
+ entityx::shared_ptr<C> component();
template <typename A>
- void unpack(boost::shared_ptr<A> &a);
+ void unpack(entityx::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);
+ void unpack(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args);
/**
* Destroy and invalidate this Entity.
*/
template <typename T>
struct ComponentAddedEvent : public Event<ComponentAddedEvent<T>> {
- ComponentAddedEvent(Entity entity, boost::shared_ptr<T> component) :
+ ComponentAddedEvent(Entity entity, entityx::shared_ptr<T> component) :
entity(entity), component(component) {}
Entity entity;
- boost::shared_ptr<T> component;
+ entityx::shared_ptr<T> component;
};
const Iterator end() const { return Iterator(manager_, predicates_, unpackers_, manager_->size()); }
template <typename A>
- View &unpack_to(boost::shared_ptr<A> &a) {
+ View &unpack_to(entityx::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 id) {
}
template <typename A, typename B, typename ... Args>
- View &unpack_to(boost::shared_ptr<A> &a, boost::shared_ptr<B> &b, Args && ... args) {
+ View &unpack_to(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
unpack_to<A>(a);
return unpack_to<B, Args ...>(b, args ...);
}
template <typename T>
struct Unpacker {
- Unpacker(EntityManager *manager, boost::shared_ptr<T> &c) : manager_(manager), c(c) {}
+ Unpacker(EntityManager *manager, entityx::shared_ptr<T> &c) : manager_(manager), c(c) {}
void operator () (Entity::Id id) {
c = manager_->component<T>(id);
private:
EntityManager *manager_;
- boost::shared_ptr<T> &c;
+ entityx::shared_ptr<T> &c;
};
View(EntityManager *manager, Predicate predicate) : manager_(manager) {
* @returns component
*/
template <typename C>
- boost::shared_ptr<C> assign(Entity::Id entity, boost::shared_ptr<C> component) {
- boost::shared_ptr<BaseComponent> base = boost::static_pointer_cast<BaseComponent>(component);
+ entityx::shared_ptr<C> assign(Entity::Id entity, entityx::shared_ptr<C> component) {
+ entityx::shared_ptr<BaseComponent> base = entityx::static_pointer_cast<BaseComponent>(component);
accomodate_component(C::family());
entity_components_.at(C::family()).at(entity) = base;
entity_component_mask_.at(entity) |= uint64_t(1) << C::family();
* @returns Newly created component.
*/
template <typename C, typename ... Args>
- boost::shared_ptr<C> assign(Entity::Id entity, Args && ... args) {
- return assign<C>(entity, boost::make_shared<C>(args ...));
+ entityx::shared_ptr<C> assign(Entity::Id entity, Args && ... args) {
+ return assign<C>(entity, entityx::make_shared<C>(args ...));
}
/**
* @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 id) {
+ entityx::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>();
+ return entityx::shared_ptr<C>();
}
- boost::shared_ptr<BaseComponent> c = entity_components_.at(C::family()).at(id);
- return boost::static_pointer_cast<C>(c);
+ entityx::shared_ptr<BaseComponent> c = entity_components_.at(C::family()).at(id);
+ return entityx::static_pointer_cast<C>(c);
}
/**
* Find Entities that have all of the specified Components.
*/
template <typename C, typename ... Components>
- View entities_with_components(boost::shared_ptr<C> &c, Components && ... args) {
+ View entities_with_components(entityx::shared_ptr<C> &c, Components && ... args) {
auto mask = component_mask(c, args ...);
return
View(this, View::ComponentMaskPredicate(entity_component_mask_, mask))
*
* Useful for fast bulk iterations.
*
- * boost::shared_ptr<Position> p;
- * boost::shared_ptr<Direction> d;
+ * entityx::shared_ptr<Position> p;
+ * entityx::shared_ptr<Direction> d;
* unpack<Position, Direction>(e, p, d);
*/
template <typename A>
- void unpack(Entity::Id id, boost::shared_ptr<A> &a) {
+ void unpack(Entity::Id id, entityx::shared_ptr<A> &a) {
a = component<A>(id);
}
*
* Useful for fast bulk iterations.
*
- * boost::shared_ptr<Position> p;
- * boost::shared_ptr<Direction> d;
+ * entityx::shared_ptr<Position> p;
+ * entityx::shared_ptr<Direction> d;
* unpack<Position, Direction>(e, p, d);
*/
template <typename A, typename B, typename ... Args>
- void unpack(Entity::Id id, boost::shared_ptr<A> &a, boost::shared_ptr<B> &b, Args && ... args) {
+ void unpack(Entity::Id id, entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
unpack<A>(id, a);
unpack<B, Args ...>(id, b, args ...);
}
}
template <typename C>
- ComponentMask component_mask(const boost::shared_ptr<C> &c) {
+ ComponentMask component_mask(const entityx::shared_ptr<C> &c) {
return component_mask<C>();
}
template <typename C1, typename C2, typename ... Components>
- ComponentMask component_mask(const boost::shared_ptr<C1> &c1, const boost::shared_ptr<C2> &c2, Components && ... args) {
+ ComponentMask component_mask(const entityx::shared_ptr<C1> &c1, const entityx::shared_ptr<C2> &c2, Components && ... args) {
return component_mask<C1>(c1) | component_mask<C2, Components ...>(c2, args...);
}
EventManager &event_manager_;
// A nested array of: components = entity_components_[family][entity]
- std::vector<std::vector<boost::shared_ptr<BaseComponent>>> entity_components_;
+ std::vector<std::vector<entityx::shared_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_;
// List of available Entity::Id IDs.
}
template <typename C>
-boost::shared_ptr<C> Entity::assign(boost::shared_ptr<C> component) {
+entityx::shared_ptr<C> Entity::assign(entityx::shared_ptr<C> component) {
return manager_->assign<C>(id_, component);
}
template <typename C, typename ... Args>
-boost::shared_ptr<C> Entity::assign(Args && ... args) {
+entityx::shared_ptr<C> Entity::assign(Args && ... args) {
return manager_->assign<C>(id_, args ...);
}
template <typename C>
-boost::shared_ptr<C> Entity::component() {
+entityx::shared_ptr<C> Entity::component() {
return manager_->component<C>(id_);
}
template <typename A>
-void Entity::unpack(boost::shared_ptr<A> &a) {
+void Entity::unpack(entityx::shared_ptr<A> &a) {
manager_->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) {
+void Entity::unpack(entityx::shared_ptr<A> &a, entityx::shared_ptr<B> &b, Args && ... args) {
manager_->unpack(id_, a, b, args ...);
}
/**
* Copyright (C) 2012 Alec Thomas <alec@swapoff.org>
* All rights reserved.
- *
+ *
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution.
- *
+ *
* Author: Alec Thomas <alec@swapoff.org>
*/
#pragma once
#include <stdint.h>
-#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/signal.hpp>
#include <boost/unordered_map.hpp>
+#include "entityx/config.h"
namespace entityx {
/// Used internally by the EventManager.
class BaseEvent {
public:
- typedef boost::shared_ptr<BaseEvent> Ptr;
+ typedef entityx::shared_ptr<BaseEvent> Ptr;
typedef uint64_t Family;
virtual ~BaseEvent() {}
template <typename Derived>
class Event : public BaseEvent {
public:
- typedef boost::shared_ptr<Event<Derived>> Ptr;
+ typedef entityx::shared_ptr<Event<Derived>> Ptr;
/// Used internally for registration.
static Family family() {
private:
typedef boost::signal<void (const BaseEvent*)> EventSignal;
- typedef boost::shared_ptr<EventSignal> EventSignalPtr;
+ typedef entityx::shared_ptr<EventSignal> EventSignalPtr;
EventSignalPtr signal_for(int id) {
auto it = handlers_.find(id);
if (it == handlers_.end()) {
- EventSignalPtr sig(boost::make_shared<EventSignal>());
+ EventSignalPtr sig(entityx::make_shared<EventSignal>());
handlers_.insert(make_pair(id, sig));
return sig;
}
return it->second;
- }
+ }
// Functor used as an event signal callback that casts to E.
template <typename E>
#include <stdint.h>
#include <cassert>
#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
+#include "entityx/config.h"
#include "entityx/Entity.h"
#include "entityx/Event.h"
* Must be called before Systems can be used.
*
* eg.
- * boost::shared_ptr<MovementSystem> movement = boost::make_shared<MovementSystem>();
+ * entityx::shared_ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
* system.add(movement);
*/
template <typename S>
- void add(boost::shared_ptr<S> system) {
+ void add(entityx::shared_ptr<S> system) {
systems_.insert(std::make_pair(S::family(), system));
}
* auto movement = system.add<MovementSystem>();
*/
template <typename S, typename ... Args>
- boost::shared_ptr<S> add(Args && ... args) {
- boost::shared_ptr<S> s = boost::make_shared<S>(args ...);
+ entityx::shared_ptr<S> add(Args && ... args) {
+ entityx::shared_ptr<S> s = entityx::make_shared<S>(args ...);
add(s);
return s;
}
/**
* Retrieve the registered System instance, if any.
*
- * boost::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
+ * entityx::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
*
* @return System instance or empty shared_ptr<S>.
*/
template <typename S>
- boost::shared_ptr<S> system() {
+ entityx::shared_ptr<S> system() {
auto it = systems_.find(S::family());
assert(it != systems_.end());
return it == systems_.end()
- ? boost::shared_ptr<S>()
- : boost::static_pointer_cast<S>(it->second);
+ ? entityx::shared_ptr<S>()
+ : entityx::static_pointer_cast<S>(it->second);
}
/**
template <typename S>
void update(double dt) {
assert(initialized_ && "SystemManager::configure() not called");
- boost::shared_ptr<S> s = system<S>();
+ entityx::shared_ptr<S> s = system<S>();
s->update(entities_, events_, dt);
}
bool initialized_ = false;
EntityManager &entities_;
EventManager &events_;
- boost::unordered_map<BaseSystem::Family, boost::shared_ptr<BaseSystem>> systems_;
+ boost::unordered_map<BaseSystem::Family, entityx::shared_ptr<BaseSystem>> systems_;
};
}
--- /dev/null
+#pragma once
+
+#cmakedefine HAVE_BOOST_SHARED_PTR 1
+#cmakedefine HAVE_STD_SHARED_PTR 1
+#cmakedefine USE_STD_SHARED_PTR 0
+
+// Which shared_ptr implementation should we use?
+#if (HAVE_STD_SHARED_PTR && USE_STD_SHARED_PTR)
+#include <memory>
+namespace entityx {
+using std::make_shared;
+using std::shared_ptr;
+using std::static_pointer_cast;
+}
+#elif HAVE_BOOST_SHARED_PTR
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+namespace entityx {
+using boost::shared_ptr;
+using boost::make_shared;
+using boost::static_pointer_cast;
+}
+#endif
--- /dev/null
+#!/bin/bash -e
+
+CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=1"
+
+if [ "$USE_STD_SHARED_PTR" = "1" ]; then
+ CMAKE_ARGS="${CMAKE_ARGS} -DUSE_STD_SHARED_PTR=1"
+ # This fails on OSX
+ if [ "$CXX" = "clang++" ]; then
+ CMAKE_ARGS="${CMAKE_ARGS} -DUSE_CPP11_STDLIB=1"
+ fi
+fi
+
+cmake ${CMAKE_ARGS}
+make
+make test