aboutsummaryrefslogtreecommitdiffstats
path: root/entityx/System.h
blob: 3d2e4b2504e83f3a6891d16c748f87aa708fc075 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 * 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 <cstdint>
#include <unordered_map>
#include <utility>
#include <cassert>
#include "entityx/config.h"
#include "entityx/Entity.h"
#include "entityx/Event.h"
#include "entityx/help/NonCopyable.h"


namespace entityx {


class SystemManager;


/**
 * Base System class. Generally should not be directly used, instead see System<Derived>.
 */
class BaseSystem : entityx::help::NonCopyable {
 public:
  typedef size_t Family;

  virtual ~BaseSystem();

  /**
   * Called once all Systems have been added to the SystemManager.
   *
   * Typically used to set up event handlers.
   */
  virtual void configure(EntityManager &entities, EventManager &events) {
	(void)entities;
    configure(events);
  }

  /**
   * Legacy configure(). Called by default implementation of configure(EntityManager&, EventManager&).
   */
  virtual void configure(EventManager &events) { (void)events; }

  /**
   * Apply System behavior.
   *
   * Called every game step.
   */
  virtual void update(EntityManager &entities, EventManager &events, TimeDelta dt) = 0;

  static Family family_counter_;

 protected:
};


/**
 * Use this class when implementing Systems.
 *
 * struct MovementSystem : public System<MovementSystem> {
 *   void update(EntityManager &entities, EventManager &events, TimeDelta dt) {
 *     // Do stuff to/with entities...
 *   }
 * }
 */
template <typename Derived>
class System : public BaseSystem {
 public:
  virtual ~System() {}

private:
  friend class SystemManager;

  static Family family() {
    static Family family = family_counter_++;
    return family;
  }
};


class SystemManager : entityx::help::NonCopyable {
 public:
  SystemManager(EntityManager &entity_manager,
                EventManager &event_manager) :
                entity_manager_(entity_manager),
                event_manager_(event_manager) {}

  /**
   * Add a System to the SystemManager.
   *
   * Must be called before Systems can be used.
   *
   * eg.
   * std::shared_ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
   * system.add(movement);
   */
  template <typename S>
  void add(std::shared_ptr<S> system) {
    systems_.insert(std::make_pair(S::family(), system));
  }

  /**
   * Add a System to the SystemManager.
   *
   * Must be called before Systems can be used.
   *
   * eg.
   * auto movement = system.add<MovementSystem>();
   */
  template <typename S, typename ... Args>
  std::shared_ptr<S> add(Args && ... args) {
    std::shared_ptr<S> s(new S(std::forward<Args>(args) ...));
    add(s);
    return s;
  }

  /**
   * Retrieve the registered System instance, if any.
   *
   *   std::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
   *
   * @return System instance or empty shared_std::shared_ptr<S>.
   */
  template <typename S>
  std::shared_ptr<S> system() {
    auto it = systems_.find(S::family());
    assert(it != systems_.end());
    return it == systems_.end()
        ? std::shared_ptr<S>()
        : std::shared_ptr<S>(std::static_pointer_cast<S>(it->second));
  }

  /**
   * Call the System::update() method for a registered system.
   */
  template <typename S>
  void update(TimeDelta dt) {
    assert(initialized_ && "SystemManager::configure() not called");
    std::shared_ptr<S> s = system<S>();
    s->update(entity_manager_, event_manager_, dt);
  }

  /**
   * Call System::update() on all registered systems.
   *
   * The order which the registered systems are updated is arbitrary but consistent,
   * meaning the order which they will be updated cannot be specified, but that order
   * will stay the same as long no systems are added or removed.
   *
   * If the order in which systems update is important, use SystemManager::update()
   * to manually specify the update order. EntityX does not yet support a way of
   * specifying priority for update_all().
   */
  void update_all(TimeDelta dt);

  /**
   * Configure the system. Call after adding all Systems.
   *
   * This is typically used to set up event handlers.
   */
  void configure();

 private:
  bool initialized_ = false;
  EntityManager &entity_manager_;
  EventManager &event_manager_;
  std::unordered_map<BaseSystem::Family, std::shared_ptr<BaseSystem>> systems_;
};

}  // namespace entityx