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::exit) {
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#endif
268 }
269
274 void update(const float dt)
275 {
277 change_scene();
278
279 if (active_scene_ != nullptr) {
280 active_scene_->update(dt);
281 }
282 }
283
286 void draw()
287 {
288 if (active_scene_ != nullptr) {
290 active_scene_->draw();
292 }
293 }
294
299 void set_timestep(std::chrono::nanoseconds ts)
300 {
301 timestep_ = ts;
302 }
303
308 std::chrono::nanoseconds get_timestep() const
309 {
310 return timestep_;
311 }
312
317 int get_fps() const
318 {
319 return fps_;
320 }
321
322private:
326 {
327 if (!has_next_scene_) {
328 return;
329 }
330
331 if (active_scene_ != nullptr) {
332 active_scene_->cleanup();
333 }
334
335 if (auto it = scenes_.find(next_scene_); it != scenes_.end()) {
336 active_scene_ = it->second;
337 active_scene_->init();
338 }
339
340 has_next_scene_ = false;
341 }
342
344 std::shared_ptr<Scene<T>> active_scene_ { nullptr };
345
348
350 bool has_next_scene_ { false };
351
353 std::unordered_map<T, std::shared_ptr<Scene<T>>> scenes_;
354
356 std::chrono::nanoseconds timestep_ { DEFAULT_TIMESTEP };
357
359 int fps_ { 0 };
360
361#ifdef __EMSCRIPTEN__
363 static SceneManager<T>* instance_;
364
366 static std::chrono::high_resolution_clock::time_point em_time_;
367
369 static void loop_emscripten()
370 {
371 if (instance_ != nullptr) {
372 auto delta_time = std::chrono::high_resolution_clock::now() - SceneManager::em_time_;
373 SceneManager::em_time_ = std::chrono::high_resolution_clock::now();
374
375 instance_->update(std::chrono::duration<float>(delta_time).count());
376 instance_->draw();
377 }
378 }
379#endif
380};
381
382#ifdef __EMSCRIPTEN__
383template <typename T> SceneManager<T>* SceneManager<T>::instance_ = nullptr;
384
385// Start time
386template <typename T> auto SceneManager<T>::em_time_ = std::chrono::high_resolution_clock::now();
387
388#endif
389
390} // namespace asw::scene
391
392#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
std::shared_ptr< Scene< T > > active_scene_
The current scene of the scene engine.
Definition scene.h:344
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
SceneManager()
Constructor for the SceneManager class.
Definition scene.h:193
bool has_next_scene_
Flag to indicate if there is a next scene to change to.
Definition scene.h:350
void draw()
Draw the current scene.
Definition scene.h:286
T next_scene_
The next scene of the scene engine.
Definition scene.h:347
void set_timestep(std::chrono::nanoseconds ts)
Set the fixed timestep for the game loop.
Definition scene.h:299
std::chrono::nanoseconds timestep_
Fixed timestep for the game loop.
Definition scene.h:356
void update(const float dt)
Update the current scene.
Definition scene.h:274
std::unordered_map< T, std::shared_ptr< Scene< T > > > scenes_
Collection of all scenes registered in the scene engine.
Definition scene.h:353
void set_next_scene(const T scene_id)
Set the next scene.
Definition scene.h:222
std::chrono::nanoseconds get_timestep() const
Get the current timestep.
Definition scene.h:308
int get_fps() const
Get the current FPS. Only applies to the managed loop.
Definition scene.h:317
int fps_
FPS Counter for managed loop.
Definition scene.h:359
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:325
Base class for game scenes.
Definition scene.h:41
SceneManager< T > & manager
Reference to the scene manager.
Definition scene.h:173
std::vector< std::shared_ptr< game::GameObject > > obj_to_create_
Objects to be created in the next frame.
Definition scene.h:180
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 > > objects_
Collection of game objects in the scene.
Definition scene.h:177
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
Core routines including main loop and initialization.
Display and window routines for the ASW library.
bool exit
When set to true, exits the main loop.
Definition core.cpp:14
void update()
Updates core module functionality.
Definition core.cpp:16
void present()
Present the window.
Definition display.cpp:107
void clear()
Clear the window.
Definition display.cpp:92
constexpr auto DEFAULT_TIMESTEP
Default time step for the game loop.
Definition scene.h:31