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
72 std::erase_if(_objects, [](const auto& obj) { return !obj->alive; });
73
74 // Update all objects in the scene
75 for (auto const& obj : _objects) {
76 if (obj->active && obj->alive) {
77 obj->update(dt);
78 }
79 }
80
81 // Create new objects
82 for (auto const& obj : _obj_to_create) {
83 _objects.push_back(obj);
84 }
85
86 // Clear the objects to create
87 _obj_to_create.clear();
88 };
89
94 virtual void draw()
95 {
96 // Sort objects by z-index
97 std::ranges::sort(_objects, std::less {}, &game::GameObject::z_index);
98
99 for (auto const& obj : _objects) {
100 if (obj->active) {
101 obj->draw();
102 }
103 }
104 };
105
111 virtual void cleanup()
112 {
113 _objects.clear();
114 };
115
120 void register_object(const std::shared_ptr<game::GameObject>& obj)
121 {
122 _objects.push_back(obj);
123 }
124
129 template <typename ObjectType, typename... Args>
130 std::shared_ptr<ObjectType> create_object(Args&&... args)
131 {
132 static_assert(std::is_base_of_v<game::GameObject, ObjectType>,
133 "ObjectType must be derived from Scene<T>");
134 static_assert(std::is_constructible_v<ObjectType, Args...>,
135 "ObjectType must be constructible with the given arguments");
136
137 auto obj = std::make_shared<ObjectType>(std::forward<Args>(args)...);
138 _obj_to_create.emplace_back(obj);
139 return obj;
140 }
141
146 const std::vector<std::shared_ptr<game::GameObject>>& get_objects() const
147 {
148 return _objects;
149 }
150
157 template <typename ObjectType> std::vector<std::shared_ptr<ObjectType>> get_object_view()
158 {
159 static_assert(std::is_base_of_v<game::GameObject, ObjectType>,
160 "ObjectType must be derived from Scene<T>");
161
162 std::vector<std::shared_ptr<ObjectType>> result;
163 for (const auto& obj : _objects) {
164 if (auto casted_obj = std::dynamic_pointer_cast<ObjectType>(obj)) {
165 result.push_back(casted_obj);
166 }
167 }
168 return result;
169 }
170
171protected:
174
175private:
177 std::vector<std::shared_ptr<game::GameObject>> _objects;
178
180 std::vector<std::shared_ptr<game::GameObject>> _obj_to_create;
181};
182
189template <typename T> class SceneManager {
190public:
194 {
195#ifdef __EMSCRIPTEN__
196 instance_ = this;
197 em_time_ = std::chrono::high_resolution_clock::now();
198#endif
199 }
200
206 template <typename SceneType, typename... Args>
207 void register_scene(const T scene_id, Args&&... args)
208 {
209 static_assert(
210 std::is_base_of_v<Scene<T>, SceneType>, "SceneType must be derived from Scene<T>");
211 static_assert(std::is_constructible_v<SceneType, Args...>,
212 "SceneType must be constructible with the given arguments");
213
214 auto scene = std::make_shared<SceneType>(std::forward<Args>(args)...);
215 _scenes[scene_id] = scene;
216 }
217
222 void set_next_scene(const T scene_id)
223 {
224 _next_scene = scene_id;
225 _has_next_scene = true;
226 }
227
234 void start()
235 {
236#ifdef __EMSCRIPTEN__
237 emscripten_set_main_loop(SceneManager::loop_emscripten, 0, 1);
238#else
239
240 using namespace std::chrono_literals;
241 std::chrono::nanoseconds lag(0ns);
242 auto time_start = std::chrono::high_resolution_clock::now();
243 auto last_second = std::chrono::high_resolution_clock::now();
244 int frames = 0;
245
246 while (!asw::core::is_exiting()) {
247 auto delta_time = std::chrono::high_resolution_clock::now() - time_start;
248 time_start = std::chrono::high_resolution_clock::now();
249 lag += std::chrono::duration_cast<std::chrono::nanoseconds>(delta_time);
250
251 while (lag >= this->_timestep) {
252 update(std::chrono::duration<float>(this->_timestep).count());
253 lag -= this->_timestep;
254 }
255
256 // Draw
257 draw();
258
259 frames++;
260
261 if (std::chrono::high_resolution_clock::now() - last_second >= 1s) {
262 _fps = frames;
263 frames = 0;
264 last_second = last_second + 1s;
265 }
266 }
267
268 // Cleanup
269 cleanup();
270#endif
271 }
272
277 void cleanup()
278 {
279 if (_active_scene != nullptr) {
280 _active_scene->cleanup();
281 }
282
283 _scenes.clear();
284 }
285
290 void update(const float dt)
291 {
292 if (asw::core::is_exiting()) {
293 return;
294 }
295
297 change_scene();
298
299 if (_active_scene != nullptr) {
300 _active_scene->update(dt);
301 }
302 }
303
306 void draw()
307 {
308 if (asw::core::is_exiting()) {
309 return;
310 }
311
312 if (_active_scene != nullptr) {
314 _active_scene->draw();
316 }
317 }
318
323 void set_timestep(std::chrono::nanoseconds ts)
324 {
325 _timestep = ts;
326 }
327
332 std::chrono::nanoseconds get_timestep() const
333 {
334 return _timestep;
335 }
336
341 int get_fps() const
342 {
343 return _fps;
344 }
345
346private:
350 {
351 if (!_has_next_scene) {
352 return;
353 }
354
355 if (_active_scene != nullptr) {
356 _active_scene->cleanup();
357 }
358
359 if (auto it = _scenes.find(_next_scene); it != _scenes.end()) {
360 _active_scene = it->second;
361 _active_scene->init();
362 }
363
364 _has_next_scene = false;
365 }
366
368 std::shared_ptr<Scene<T>> _active_scene { nullptr };
369
372
374 bool _has_next_scene { false };
375
377 std::unordered_map<T, std::shared_ptr<Scene<T>>> _scenes;
378
380 std::chrono::nanoseconds _timestep { DEFAULT_TIMESTEP };
381
383 int _fps { 0 };
384
385#ifdef __EMSCRIPTEN__
387 static SceneManager<T>* instance_;
388
390 static std::chrono::high_resolution_clock::time_point em_time_;
391
393 static void loop_emscripten()
394 {
395 if (instance_ != nullptr) {
396 auto delta_time = std::chrono::high_resolution_clock::now() - SceneManager::em_time_;
397 SceneManager::em_time_ = std::chrono::high_resolution_clock::now();
398
399 instance_->update(std::chrono::duration<float>(delta_time).count());
400 instance_->draw();
401 }
402 }
403#endif
404};
405
406#ifdef __EMSCRIPTEN__
407template <typename T> SceneManager<T>* SceneManager<T>::instance_ = nullptr;
408
409// Start time
410template <typename T> auto SceneManager<T>::em_time_ = std::chrono::high_resolution_clock::now();
411
412#endif
413
414} // namespace asw::scene
415
416#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:189
void cleanup()
Destroy the scene manager and clean up resources. This function is called when the scene manager is d...
Definition scene.h:277
bool _has_next_scene
Flag to indicate if there is a next scene to change to.
Definition scene.h:374
void start()
Main loop for the scene engine. If this is not enough, or you want to define your own loop,...
Definition scene.h:234
T _next_scene
The next scene of the scene engine.
Definition scene.h:371
std::shared_ptr< Scene< T > > _active_scene
The current scene of the scene engine.
Definition scene.h:368
SceneManager()
Constructor for the SceneManager class.
Definition scene.h:193
void draw()
Draw the current scene.
Definition scene.h:306
void set_timestep(std::chrono::nanoseconds ts)
Set the fixed timestep for the game loop.
Definition scene.h:323
std::unordered_map< T, std::shared_ptr< Scene< T > > > _scenes
Collection of all scenes registered in the scene engine.
Definition scene.h:377
void update(const float dt)
Update the current scene.
Definition scene.h:290
std::chrono::nanoseconds _timestep
Fixed timestep for the game loop.
Definition scene.h:380
void set_next_scene(const T scene_id)
Set the next scene.
Definition scene.h:222
int _fps
FPS Counter for managed loop.
Definition scene.h:383
std::chrono::nanoseconds get_timestep() const
Get the current timestep.
Definition scene.h:332
int get_fps() const
Get the current FPS. Only applies to the managed loop.
Definition scene.h:341
void register_scene(const T scene_id, Args &&... args)
Register a scene to be managed by the scene engine.
Definition scene.h:207
void change_scene()
Change the current scene to the next scene.
Definition scene.h:349
Base class for game scenes.
Definition scene.h:41
SceneManager< T > & manager
Reference to the scene manager.
Definition scene.h:173
virtual void draw()
Draw the game scene.
Definition scene.h:94
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:120
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:146
virtual void cleanup()
Handle input for the game scene.
Definition scene.h:111
std::vector< std::shared_ptr< game::GameObject > > _obj_to_create
Objects to be created in the next frame.
Definition scene.h:180
std::vector< std::shared_ptr< ObjectType > > get_object_view()
Get game objects of a specific type in the scene.
Definition scene.h:157
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:130
std::vector< std::shared_ptr< game::GameObject > > _objects
Collection of game objects in the scene.
Definition scene.h:177
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