ASW Lib
A.D.S. Games SDL Wrapper Library. A library targeted at Allegro4 users who want to switch to SDL3 and use modern c++.
Loading...
Searching...
No Matches
scene.h
Go to the documentation of this file.
1
8
9#ifndef ASW_SCENE_H
10#define ASW_SCENE_H
11
12#include <algorithm>
13#include <chrono>
14#include <iostream>
15#include <memory>
16#include <ranges>
17#include <unordered_map>
18#include <vector>
19
20#include "./core.h"
21#include "./display.h"
22#include "./game.h"
23
24#ifdef __EMSCRIPTEN__
25#include <emscripten.h>
26#endif
27
28namespace asw::scene {
29
31constexpr auto DEFAULT_TIMESTEP = std::chrono::milliseconds(8);
32
34template <typename T> class SceneManager;
35
41template <typename T> class Scene {
42public:
49 {
50 }
51
53 virtual ~Scene() = default;
54
60 virtual void init() {
61 // Default implementation does nothing
62 };
63
69 virtual void update(float dt)
70 {
71 // Erase inactive objects. Scanning first keeps the compaction pass off
72 // frames where nothing actually died.
73 if (std::ranges::any_of(_objects, [](const auto& obj) { return !obj->alive; })) {
74 std::erase_if(_objects, [](const auto& obj) { return !obj->alive; });
75 }
76
77 // Update all objects in the scene
78 for (auto const& obj : _objects) {
79 if (obj->active && obj->alive) {
80 obj->update(dt);
81 }
82 }
83
84 // Create new objects
85 if (!_obj_to_create.empty()) {
86 _objects.reserve(_objects.size() + _obj_to_create.size());
87 _objects.insert(_objects.end(), _obj_to_create.begin(), _obj_to_create.end());
88 }
89
90 // Clear the objects to create
91 _obj_to_create.clear();
92 };
93
98 virtual void draw()
99 {
100 // Sort objects by z-index. The check is a linear read, so already
101 // ordered scenes skip the sort entirely.
102 if (!std::ranges::is_sorted(_objects, std::less {}, &game::GameObject::z_index)) {
103 std::ranges::sort(_objects, std::less {}, &game::GameObject::z_index);
104 }
105
106 for (auto const& obj : _objects) {
107 if (obj->active) {
108 obj->draw();
109 }
110 }
111 };
112
118 virtual void cleanup()
119 {
120 _objects.clear();
121 };
122
127 void register_object(const std::shared_ptr<game::GameObject>& obj)
128 {
129 _objects.push_back(obj);
130 }
131
136 template <typename ObjectType, typename... Args>
137 std::shared_ptr<ObjectType> create_object(Args&&... args)
138 {
139 static_assert(std::is_base_of_v<game::GameObject, ObjectType>,
140 "ObjectType must be derived from Scene<T>");
141 static_assert(std::is_constructible_v<ObjectType, Args...>,
142 "ObjectType must be constructible with the given arguments");
143
144 auto obj = std::make_shared<ObjectType>(std::forward<Args>(args)...);
145 _obj_to_create.emplace_back(obj);
146 return obj;
147 }
148
153 const std::vector<std::shared_ptr<game::GameObject>>& get_objects() const
154 {
155 return _objects;
156 }
157
164 template <typename ObjectType> std::vector<std::shared_ptr<ObjectType>> get_object_view()
165 {
166 static_assert(std::is_base_of_v<game::GameObject, ObjectType>,
167 "ObjectType must be derived from Scene<T>");
168
169 std::vector<std::shared_ptr<ObjectType>> result;
170 for (const auto& obj : _objects) {
171 if (auto casted_obj = std::dynamic_pointer_cast<ObjectType>(obj)) {
172 result.push_back(casted_obj);
173 }
174 }
175 return result;
176 }
177
178protected:
181
182private:
184 std::vector<std::shared_ptr<game::GameObject>> _objects;
185
187 std::vector<std::shared_ptr<game::GameObject>> _obj_to_create;
188};
189
196template <typename T> class SceneManager {
197public:
201 {
202#ifdef __EMSCRIPTEN__
203 instance_ = this;
204 em_time_ = std::chrono::high_resolution_clock::now();
205#endif
206 }
207
213 template <typename SceneType, typename... Args>
214 void register_scene(const T scene_id, Args&&... args)
215 {
216 static_assert(
217 std::is_base_of_v<Scene<T>, SceneType>, "SceneType must be derived from Scene<T>");
218 static_assert(std::is_constructible_v<SceneType, Args...>,
219 "SceneType must be constructible with the given arguments");
220
221 auto scene = std::make_shared<SceneType>(std::forward<Args>(args)...);
222 _scenes[scene_id] = scene;
223 }
224
229 void set_next_scene(const T scene_id)
230 {
231 _next_scene = scene_id;
232 _has_next_scene = true;
233 }
234
241 void start()
242 {
243#ifdef __EMSCRIPTEN__
244 emscripten_set_main_loop(SceneManager::loop_emscripten, 0, 1);
245#else
246
247 using namespace std::chrono_literals;
248 std::chrono::nanoseconds lag(0ns);
249 auto time_start = std::chrono::high_resolution_clock::now();
250 auto last_second = std::chrono::high_resolution_clock::now();
251 int frames = 0;
252
253 while (!asw::core::is_exiting()) {
254 const auto now = std::chrono::high_resolution_clock::now();
255 auto delta_time = now - time_start;
256 time_start = now;
257 lag += std::chrono::duration_cast<std::chrono::nanoseconds>(delta_time);
258
259 while (lag >= this->_timestep) {
260 update(std::chrono::duration<float>(this->_timestep).count());
261 lag -= this->_timestep;
262 }
263
264 // Draw
265 draw();
266
267 frames++;
268
269 if (now - last_second >= 1s) {
270 _fps = frames;
271 frames = 0;
272 last_second = last_second + 1s;
273 }
274 }
275
276 // Cleanup
277 cleanup();
278#endif
279 }
280
285 void cleanup()
286 {
287 if (_active_scene != nullptr) {
288 _active_scene->cleanup();
289 }
290
291 _scenes.clear();
292 }
293
298 void update(const float dt)
299 {
300 if (asw::core::is_exiting()) {
301 return;
302 }
303
305 change_scene();
306
307 if (_active_scene != nullptr) {
308 _active_scene->update(dt);
309 }
310 }
311
314 void draw()
315 {
316 if (asw::core::is_exiting()) {
317 return;
318 }
319
320 if (_active_scene != nullptr) {
322 _active_scene->draw();
324 }
325 }
326
331 void set_timestep(std::chrono::nanoseconds ts)
332 {
333 _timestep = ts;
334 }
335
340 std::chrono::nanoseconds get_timestep() const
341 {
342 return _timestep;
343 }
344
349 int get_fps() const
350 {
351 return _fps;
352 }
353
354private:
358 {
359 if (!_has_next_scene) {
360 return;
361 }
362
363 if (_active_scene != nullptr) {
364 _active_scene->cleanup();
365 }
366
367 if (auto it = _scenes.find(_next_scene); it != _scenes.end()) {
368 _active_scene = it->second;
369 _active_scene->init();
370 }
371
372 _has_next_scene = false;
373 }
374
376 std::shared_ptr<Scene<T>> _active_scene { nullptr };
377
380
382 bool _has_next_scene { false };
383
385 std::unordered_map<T, std::shared_ptr<Scene<T>>> _scenes;
386
388 std::chrono::nanoseconds _timestep { DEFAULT_TIMESTEP };
389
391 int _fps { 0 };
392
393#ifdef __EMSCRIPTEN__
395 static SceneManager<T>* instance_;
396
398 static std::chrono::high_resolution_clock::time_point em_time_;
399
401 static void loop_emscripten()
402 {
403 if (instance_ != nullptr) {
404 const auto now = std::chrono::high_resolution_clock::now();
405 auto delta_time = now - SceneManager::em_time_;
406 SceneManager::em_time_ = now;
407
408 instance_->update(std::chrono::duration<float>(delta_time).count());
409 instance_->draw();
410 }
411 }
412#endif
413};
414
415#ifdef __EMSCRIPTEN__
416template <typename T> SceneManager<T>* SceneManager<T>::instance_ = nullptr;
417
418// Start time
419template <typename T> auto SceneManager<T>::em_time_ = std::chrono::high_resolution_clock::now();
420
421#endif
422
423} // namespace asw::scene
424
425#endif // ASW_SCENE_H
int z_index
The layer that the object is on.
Definition game.h:87
Forward declaration of the SceneManager class.
Definition scene.h:196
void cleanup()
Destroy the scene manager and clean up resources. This function is called when the scene manager is d...
Definition scene.h:285
bool _has_next_scene
Flag to indicate if there is a next scene to change to.
Definition scene.h:382
void start()
Main loop for the scene engine. If this is not enough, or you want to define your own loop,...
Definition scene.h:241
T _next_scene
The next scene of the scene engine.
Definition scene.h:379
std::shared_ptr< Scene< T > > _active_scene
The current scene of the scene engine.
Definition scene.h:376
SceneManager()
Constructor for the SceneManager class.
Definition scene.h:200
void draw()
Draw the current scene.
Definition scene.h:314
void set_timestep(std::chrono::nanoseconds ts)
Set the fixed timestep for the game loop.
Definition scene.h:331
std::unordered_map< T, std::shared_ptr< Scene< T > > > _scenes
Collection of all scenes registered in the scene engine.
Definition scene.h:385
void update(const float dt)
Update the current scene.
Definition scene.h:298
std::chrono::nanoseconds _timestep
Fixed timestep for the game loop.
Definition scene.h:388
void set_next_scene(const T scene_id)
Set the next scene.
Definition scene.h:229
int _fps
FPS Counter for managed loop.
Definition scene.h:391
std::chrono::nanoseconds get_timestep() const
Get the current timestep.
Definition scene.h:340
int get_fps() const
Get the current FPS. Only applies to the managed loop.
Definition scene.h:349
void register_scene(const T scene_id, Args &&... args)
Register a scene to be managed by the scene engine.
Definition scene.h:214
void change_scene()
Change the current scene to the next scene.
Definition scene.h:357
Base class for game scenes.
Definition scene.h:41
SceneManager< T > & manager
Reference to the scene manager.
Definition scene.h:180
virtual void draw()
Draw the game scene.
Definition scene.h:98
Scene(SceneManager< T > &manager)
Constructor for the Scene class.
Definition scene.h:47
void register_object(const std::shared_ptr< game::GameObject > &obj)
Add a game object to the scene.
Definition scene.h:127
virtual void update(float dt)
Update the game scene.
Definition scene.h:69
virtual void init()
Initialize the game scene.
Definition scene.h:60
const std::vector< std::shared_ptr< game::GameObject > > & get_objects() const
Get game objects in the scene.
Definition scene.h:153
virtual void cleanup()
Handle input for the game scene.
Definition scene.h:118
std::vector< std::shared_ptr< game::GameObject > > _obj_to_create
Objects to be created in the next frame.
Definition scene.h:187
std::vector< std::shared_ptr< ObjectType > > get_object_view()
Get game objects of a specific type in the scene.
Definition scene.h:164
virtual ~Scene()=default
Destructor for the Scene class.
std::shared_ptr< ObjectType > create_object(Args &&... args)
Create a new game object in the scene.
Definition scene.h:137
std::vector< std::shared_ptr< game::GameObject > > _objects
Collection of game objects in the scene.
Definition scene.h:184
Core routines including main loop and initialization.
Display and window routines for the ASW library.
void update()
Updates core module functionality.
Definition core.cpp:21
bool is_exiting()
Return exiting status.
Definition core.cpp:218
void present()
Present the window.
Definition display.cpp:169
void clear()
Clear the window.
Definition display.cpp:154
constexpr auto DEFAULT_TIMESTEP
Default time step for the game loop.
Definition scene.h:31