supertux
game_object_manager.hpp
1 // SuperTux
2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 // 2018 Ingo Ruhnke <grumbel@gmail.com>
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18 #ifndef HEADER_SUPERTUX_SUPERTUX_GAME_OBJECT_MANAGER_HPP
19 #define HEADER_SUPERTUX_SUPERTUX_GAME_OBJECT_MANAGER_HPP
20 
21 #include <functional>
22 #include <typeindex>
23 #include <unordered_map>
24 #include <vector>
25 
26 #include "supertux/game_object.hpp"
27 #include "util/uid_generator.hpp"
28 
29 class DrawingContext;
30 class TileMap;
31 
32 template<class T> class GameObjectRange;
33 
35 {
36 public:
37  static bool s_draw_solids_only;
38 
39 private:
40  struct NameResolveRequest
41  {
42  std::string name;
43  std::function<void (UID)> callback;
44  };
45 
46 public:
48  virtual ~GameObjectManager();
49 
51  GameObject& add_object(std::unique_ptr<GameObject> object);
52  void clear_objects();
53 
54  template<typename T, typename... Args>
55  T& add(Args&&... args)
56  {
57  auto obj = std::make_unique<T>(std::forward<Args>(args)...);
58  T& obj_ref = *obj;
59  add_object(std::move(obj));
60  return obj_ref;
61  }
62 
63  void update(float dt_sec);
64  void draw(DrawingContext& context);
65 
66  const std::vector<std::unique_ptr<GameObject> >& get_objects() const;
67 
69  void flush_game_objects();
70 
71  float get_width() const;
72  float get_height() const;
73 
75  float get_tiles_width() const;
76 
78  float get_tiles_height() const;
79 
81  virtual bool before_object_add(GameObject& object) = 0;
82 
84  virtual void before_object_remove(GameObject& object) = 0;
85 
86  template<class T>
87  GameObjectRange<T> get_objects_by_type() const
88  {
89  return GameObjectRange<T>(*this);
90  }
91 
92  const std::vector<GameObject*>&
93  get_objects_by_type_index(std::type_index type_idx) const
94  {
95  auto it = m_objects_by_type_index.find(type_idx);
96  if (it == m_objects_by_type_index.end()) {
97  // use a dummy return value to avoid making this method non-const
98  static std::vector<GameObject*> dummy;
99  return dummy;
100  } else {
101  return it->second;
102  }
103  }
104 
105  template<class T>
106  T& get_singleton_by_type() const
107  {
108  const auto& range = get_objects_by_type<T>();
109  assert(range.begin() != range.end());
110  assert(range.begin()->is_singleton());
111  return *range.begin();
112  }
113 
114  template<class T>
115  T* get_object_by_uid(const UID& uid) const
116  {
117  auto it = m_objects_by_uid.find(uid);
118  if (it == m_objects_by_uid.end())
119  {
120  // FIXME: Is this a good idea? Should gameobjects be made
121  // accessible even when not fully inserted into the manager?
122  for (auto&& itnew : m_gameobjects_new)
123  {
124  if (itnew->get_uid() == uid)
125  return static_cast<T*>(itnew.get());
126  }
127  return nullptr;
128  }
129  else
130  {
131 #ifdef NDEBUG
132  return static_cast<T*>(it->second);
133 #else
134  // Since uids should be unique, there should be no need to guess
135  // the type, thus we assert() when the object type is not what
136  // we expected.
137  auto ptr = dynamic_cast<T*>(it->second);
138  assert(ptr != nullptr);
139  return ptr;
140 #endif
141  }
142  }
143 
148  void request_name_resolve(const std::string& name, std::function<void (UID)> callback);
149 
150  template<class T>
151  T* get_object_by_name(const std::string& name) const
152  {
153  auto it = m_objects_by_name.find(name);
154  if (it == m_objects_by_name.end())
155  {
156  return nullptr;
157  }
158  else
159  {
160  return dynamic_cast<T*>(it->second);
161  }
162  }
163 
165  template<class T>
166  int get_object_count(std::function<bool(const T&)> predicate = nullptr) const
167  {
168  int total = 0;
169  for (const auto& obj : m_gameobjects) {
170  auto object = dynamic_cast<T*>(obj.get());
171  if (object && (predicate == nullptr || predicate(*object)))
172  {
173  total += 1;
174  }
175  }
176  return total;
177  }
178 
179  const std::vector<TileMap*>& get_solid_tilemaps() const { return m_solid_tilemaps; }
180 
181 protected:
182  void process_resolve_requests();
183 
184  template<class T>
185  T* get_object_by_type() const
186  {
187  const auto& range = get_objects_by_type<T>();
188  if (range.begin() == range.end()) {
189  return nullptr;
190  } else {
191  return &*range.begin();
192  }
193  }
194 
195 private:
196  void this_before_object_add(GameObject& object);
197  void this_before_object_remove(GameObject& object);
198 
199 private:
200  UIDGenerator m_uid_generator;
201 
202  std::vector<std::unique_ptr<GameObject>> m_gameobjects;
203 
205  std::vector<std::unique_ptr<GameObject>> m_gameobjects_new;
206 
208  std::vector<TileMap*> m_solid_tilemaps;
209 
210  std::unordered_map<std::string, GameObject*> m_objects_by_name;
211  std::unordered_map<UID, GameObject*> m_objects_by_uid;
212  std::unordered_map<std::type_index, std::vector<GameObject*> > m_objects_by_type_index;
213 
214  std::vector<NameResolveRequest> m_name_resolve_requests;
215 
216 private:
217  GameObjectManager(const GameObjectManager&) = delete;
218  GameObjectManager& operator=(const GameObjectManager&) = delete;
219 };
220 
221 #include "supertux/game_object_iterator.hpp"
222 
223 #endif
224 
225 /* EOF */
virtual bool before_object_add(GameObject &object)=0
Hook that is called before an object is added to the vector.
Definition: game_object_iterator.hpp:110
Definition: uid_generator.hpp:22
float get_tiles_height() const
returns the height (in tiles) of a worldmap
Definition: game_object_manager.cpp:267
Definition: game_object_manager.hpp:34
GameObject & add_object(std::unique_ptr< GameObject > object)
Queue an object up to be added to the object list.
Definition: game_object_manager.cpp:79
virtual void before_object_remove(GameObject &object)=0
Hook that is called before an object is removed from the vector.
void flush_game_objects()
Commit the queued up additions and deletions to the object list.
Definition: game_object_manager.cpp:144
Definition: uid.hpp:37
int get_object_count(std::function< bool(const T &)> predicate=nullptr) const
Get total number of GameObjects of given type.
Definition: game_object_manager.hpp:166
Base class for all the things that make up Levels&#39; Sectors.
Definition: game_object.hpp:46
void request_name_resolve(const std::string &name, std::function< void(UID)> callback)
Register a callback to be called once the given name can be resolsed to a UID.
Definition: game_object_manager.cpp:46
This class is responsible for drawing the level tiles.
Definition: tilemap.hpp:39
This class provides functions for drawing things on screen.
Definition: drawing_context.hpp:42
float get_tiles_width() const
returns the width (in tiles) of a worldmap
Definition: game_object_manager.cpp:256