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/World.cc)
+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
-Entity-Component (EC) systems are a form of decomposition that completely decouple 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.
+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.
+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.
## Overview
-In EntityX data associated with an entity is called a `Component`. `Systems` use components to implement behavior and can utilize as many components as necessary. An `EventManager` allows systems to interact without being tightly coupled. Finally, a `World` object ties all of the systems together for convenience.
+In EntityX data associated with an entity is called a `Component`. `Systems` encapsulate logic and can use as many component types as necessary. An `EventManager` allows systems to interact without being tightly coupled. Finally, a `Manager` object ties all of the systems together for convenience.
As an example, a physics system might need *position* and *mass* data, while a collision system might only need *position* - the data would be logically separated into two components, but usable by any system. The physics system might emit *collision* events whenever two entities collide.
## Tutorial
-
+Following is some skeleton code that implements `Position` and `Direction` components, a `MovementSystem` using these data components, and a `CollisionSystem` that emits `Collision` events when two entities collide.
### Entities
#### Querying entities and their components
-To retrieve a component associated with an entity use ``EntityManager::component()``:
-
-```
-boost::shared_ptr<Position> position = entities.component<Position>();
-if (position) {
- // Do stuff with position
-}
-```
-
To query all components with a set of components assigned use ``EntityManager::entities_with_components()``. This method will return only those entities that have *all* of the specified components associated with them, assigning each component pointer to the corresponding component instance:
```
}
```
+To retrieve a component associated with an entity use ``EntityManager::component()``:
+
+```
+boost::shared_ptr<Position> position = entities.component<Position>();
+if (position) {
+ // Do stuff with position
+}
+```
+
### Systems (implementing behavior)
Systems implement behavior using one or more components. Implementations are subclasses of `System<T>` and *must* implement the `update()` method, as shown below.
```
struct MovementSystem : public System<MovementSystem> {
void update(EntityManager &es, EventManager &events, double dt) override {
- Position *position;
- Direction *direction;
+ boost::shared_ptr<Position> position;
+ boost::shared_ptr<Direction> direction;
for (auto entity : es.entities_with_components(position, direction)) {
position->x += direction->x;
position->y += direction->y;
};
```
-Note that a single class can receive any number of types of events by implementing a ``receive(const EventType &)`` method for each event type.
+***Note:** a single class can receive any number of types of events by implementing a ``receive(const EventType &)`` method for each event type.*
Finally, we subscribe our receiver to collision events:
events.subscribe<Collision>(debug_collisions);
```
-### World (tying it all together)
+### Manager (tying it all together)
-Managing systems, components and entities can be streamlined by subclassing `World`. It is not necessary, but it provides callbacks for configuring systems, initializing entities and the world, and so on.
+Managing systems, components and entities can be streamlined by subclassing `Manager`. It is not necessary, but it provides callbacks for configuring systems, initializing entities, and so on.
-To use it, subclass `World` and implement `configure()`, `initialize()` and `update()`:
+To use it, subclass `Manager` and implement `configure()`, `initialize()` and `update()`:
```
-class GameWorld : public World {
+class GameManager : public Manager {
protected:
void configure() {
system_manager.add<MovementSystem>();
EntityX has the following build and runtime requirements:
-- A C++ compiler that supports a basic set of C++11 features (eg. recent clang, recent gcc).
+- A C++ compiler that supports a basic set of C++11 features (ie. recent clang, recent gcc, but **NOT** Visual C++).
- [CMake](http://cmake.org/)
- [Boost](http://boost.org) `1.48.0` or higher (links against `boost::signals`).
- [Glog](http://code.google.com/p/google-glog/) (tested with `0.3.2`).
--- /dev/null
+/**
+ * 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 "Manager.h"
+
+namespace entity {
+
+void Manager::start() {
+ configure();
+ system_manager.configure();
+ initialize();
+}
+
+void Manager::run() {
+ running_ = true;
+ double dt;
+ timer_.restart();
+ while (running_) {
+ dt = timer_.elapsed();
+ timer_.restart();
+ update(dt);
+ }
+}
+
+void Manager::stop() {
+ running_ = false;
+}
+
+}
--- /dev/null
+/**
+ * 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 <boost/timer.hpp>
+#include "entityx/Entity.h"
+#include "entityx/Event.h"
+#include "entityx/System.h"
+
+namespace entity {
+
+class Manager {
+ public:
+ Manager() : entity_manager(event_manager), system_manager(entity_manager, event_manager) {}
+ virtual ~Manager() {}
+
+ void start();
+ void run();
+ void stop();
+
+ protected:
+ /**
+ * Configure the world.
+ *
+ * This is called once on Manager initialization. It is typically used to add Systems to the world, load permanent
+ * resources, global configuration, etc.
+ */
+ virtual void configure() = 0;
+
+ /**
+ * Initialize the entities and events in the world.
+ *
+ * Typically used when
+ */
+ virtual void initialize() = 0;
+
+ /**
+ * Update the world.
+ */
+ virtual void update(double dt) = 0;
+
+ EventManager event_manager;
+ EntityManager entity_manager;
+ SystemManager system_manager;
+
+ private:
+ boost::timer timer_;
+ bool running_ = false;
+};
+
+}
#include <vector>
#include <glog/logging.h>
#include <gtest/gtest.h>
-#include "entityx/World.h"
+#include "entityx/Manager.h"
#include "entityx/System.h"
};
-class TestWorld : public entity::World {
+class TestManager : public entity::Manager {
public:
std::vector<Entity> entities;
class SystemManagerTest : public ::testing::Test {
protected:
- TestWorld world;
+ TestManager manager;
virtual void SetUp() override {
- world.start();
+ manager.start();
}
};
TEST_F(SystemManagerTest, TestConstructSystemWithArgs) {
- world.sm().add<MovementSystem>("movement");
- world.sm().configure();
+ manager.sm().add<MovementSystem>("movement");
+ manager.sm().configure();
- ASSERT_EQ("movement", world.sm().system<MovementSystem>()->label);
+ ASSERT_EQ("movement", manager.sm().system<MovementSystem>()->label);
}
TEST_F(SystemManagerTest, TestApplySystem) {
- world.sm().add<MovementSystem>();
- world.sm().configure();
+ manager.sm().add<MovementSystem>();
+ manager.sm().configure();
- world.sm().update<MovementSystem>(0.0);
+ manager.sm().update<MovementSystem>(0.0);
shared_ptr<Position> position;
shared_ptr<Direction> direction;
- for (auto entity : world.entities) {
- world.em().unpack<Position, Direction>(entity, position, direction);
+ for (auto entity : manager.entities) {
+ manager.em().unpack<Position, Direction>(entity, position, direction);
if (position && direction) {
ASSERT_FLOAT_EQ(2.0, position->x);
ASSERT_FLOAT_EQ(3.0, position->y);
+++ /dev/null
-/**
- * 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 "World.h"
-
-namespace entity {
-
-void World::start() {
- configure();
- system_manager.configure();
- initialize();
-}
-
-void World::run() {
- running_ = true;
- double dt;
- timer_.restart();
- while (running_) {
- dt = timer_.elapsed();
- timer_.restart();
- update(dt);
- }
-}
-
-void World::stop() {
- running_ = false;
-}
-
-}
+++ /dev/null
-/**
- * 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 <boost/timer.hpp>
-#include "entityx/Entity.h"
-#include "entityx/Event.h"
-#include "entityx/System.h"
-
-namespace entity {
-
-class World {
- public:
- World() : entity_manager(event_manager), system_manager(entity_manager, event_manager) {}
- virtual ~World() {}
-
- void start();
- void run();
- void stop();
-
- protected:
- /**
- * Configure the world.
- *
- * This is called once on World initialization. It is typically used to add Systems to the world, load permanent
- * resources, global configuration, etc.
- */
- virtual void configure() = 0;
-
- /**
- * Initialize the entities and events in the world.
- *
- * Typically used when
- */
- virtual void initialize() = 0;
-
- /**
- * Update the world.
- */
- virtual void update(double dt) = 0;
-
- EventManager event_manager;
- EntityManager entity_manager;
- SystemManager system_manager;
-
- private:
- boost::timer timer_;
- bool running_ = false;
-};
-
-}