Implement scene system; move render loop from Game to Engine
This commit is contained in:
parent
b4635cdb99
commit
48b70b0bc8
6 changed files with 196 additions and 89 deletions
|
|
@ -47,12 +47,10 @@ export namespace rutile
|
||||||
return sdl::AppResult::Continue;
|
return sdl::AppResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdl::AppResult handle_event(const sdl::Event& event)
|
sdl::AppResult handle_event(const sdl::Event& event) const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!engine_->handle_event(event)) {
|
engine_->handle_event(event);
|
||||||
game_->handle_event(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error& e) {
|
catch (const std::runtime_error& e) {
|
||||||
std::cerr << "Unhandled exception during event handling: " << e.what() << '\n';
|
std::cerr << "Unhandled exception during event handling: " << e.what() << '\n';
|
||||||
|
|
@ -62,12 +60,11 @@ export namespace rutile
|
||||||
return engine_->keep_running() ? sdl::AppResult::Continue : sdl::AppResult::Success;
|
return engine_->keep_running() ? sdl::AppResult::Continue : sdl::AppResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdl::AppResult iterate()
|
sdl::AppResult iterate() const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
engine_->update();
|
engine_->update();
|
||||||
game_->update();
|
engine_->render();
|
||||||
game_->render();
|
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error& e) {
|
catch (const std::runtime_error& e) {
|
||||||
std::cerr << "Unhandled exception during updating: " << e.what() << '\n';
|
std::cerr << "Unhandled exception during updating: " << e.what() << '\n';
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import std;
|
||||||
import rutile.config;
|
import rutile.config;
|
||||||
import rutile.core.render_server;
|
import rutile.core.render_server;
|
||||||
import rutile.core.resource_server;
|
import rutile.core.resource_server;
|
||||||
|
import rutile.core.scenes.scene_manager;
|
||||||
import rutile.core.ui.ui_server;
|
import rutile.core.ui.ui_server;
|
||||||
import wrappers.sdl;
|
import wrappers.sdl;
|
||||||
|
|
||||||
|
|
@ -16,7 +17,7 @@ export namespace rutile
|
||||||
class Engine
|
class Engine
|
||||||
{
|
{
|
||||||
// Whether this class is currently instantiated (to prevent multiple instances)
|
// Whether this class is currently instantiated (to prevent multiple instances)
|
||||||
static bool instantiated_;
|
static Engine* instance_;
|
||||||
|
|
||||||
// If this is set to false, the application will exit
|
// If this is set to false, the application will exit
|
||||||
bool keep_running_ = true;
|
bool keep_running_ = true;
|
||||||
|
|
@ -24,6 +25,7 @@ export namespace rutile
|
||||||
sdl::Window window_;
|
sdl::Window window_;
|
||||||
RenderServer render_server_;
|
RenderServer render_server_;
|
||||||
ResourceServer resource_server_;
|
ResourceServer resource_server_;
|
||||||
|
SceneManager scene_manager_;
|
||||||
UIServer ui_server_;
|
UIServer ui_server_;
|
||||||
|
|
||||||
// Private constructor
|
// Private constructor
|
||||||
|
|
@ -33,7 +35,7 @@ export namespace rutile
|
||||||
resource_server_{render_server_.get_renderer()},
|
resource_server_{render_server_.get_renderer()},
|
||||||
ui_server_{render_server_.get_renderer(), window_}
|
ui_server_{render_server_.get_renderer(), window_}
|
||||||
{
|
{
|
||||||
instantiated_ = true;
|
instance_ = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -47,13 +49,13 @@ export namespace rutile
|
||||||
|
|
||||||
~Engine()
|
~Engine()
|
||||||
{
|
{
|
||||||
instantiated_ = false;
|
instance_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Engine> create()
|
static std::unique_ptr<Engine> create()
|
||||||
{
|
{
|
||||||
// Prevent the class from being instantiated multiple times
|
// Prevent the class from being instantiated multiple times
|
||||||
assert(!instantiated_);
|
assert(!instance_);
|
||||||
|
|
||||||
auto [sdl_window, sdl_renderer] = sdl::create_window_and_renderer(
|
auto [sdl_window, sdl_renderer] = sdl::create_window_and_renderer(
|
||||||
config::get_window_title(),
|
config::get_window_title(),
|
||||||
|
|
@ -72,6 +74,13 @@ export namespace rutile
|
||||||
// NOLINTEND
|
// NOLINTEND
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get singleton instance of engine
|
||||||
|
static Engine& get()
|
||||||
|
{
|
||||||
|
assert(instance_);
|
||||||
|
return *instance_;
|
||||||
|
}
|
||||||
|
|
||||||
bool keep_running() const
|
bool keep_running() const
|
||||||
{
|
{
|
||||||
return keep_running_;
|
return keep_running_;
|
||||||
|
|
@ -92,6 +101,11 @@ export namespace rutile
|
||||||
return resource_server_;
|
return resource_server_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SceneManager& get_scene_manager()
|
||||||
|
{
|
||||||
|
return scene_manager_;
|
||||||
|
}
|
||||||
|
|
||||||
UIServer& get_ui_server()
|
UIServer& get_ui_server()
|
||||||
{
|
{
|
||||||
return ui_server_;
|
return ui_server_;
|
||||||
|
|
@ -110,11 +124,38 @@ export namespace rutile
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto scene = scene_manager_.get_current_scene();
|
||||||
|
if (scene && scene->handle_event(event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update()
|
void update() const
|
||||||
{
|
{
|
||||||
|
// Update current scene
|
||||||
|
if (const auto scene = scene_manager_.get_current_scene()) {
|
||||||
|
scene->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update UI
|
||||||
|
ui_server_.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void render() const
|
||||||
|
{
|
||||||
|
render_server_.start_frame();
|
||||||
|
|
||||||
|
// Render current scene
|
||||||
|
if (const auto scene = scene_manager_.get_current_scene()) {
|
||||||
|
scene->render(render_server_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render UI
|
||||||
|
ui_server_.render();
|
||||||
|
|
||||||
|
render_server_.finish_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown()
|
void shutdown()
|
||||||
|
|
@ -122,5 +163,5 @@ export namespace rutile
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Engine::instantiated_ = false;
|
Engine* Engine::instance_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
src/rutile/core/scenes/base_scene.cppm
Normal file
27
src/rutile/core/scenes/base_scene.cppm
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
module;
|
||||||
|
|
||||||
|
export module rutile.core.scenes.base_scene;
|
||||||
|
|
||||||
|
import std;
|
||||||
|
import rutile.core.render_server;
|
||||||
|
import rutile.core.resource_server;
|
||||||
|
import wrappers.sdl;
|
||||||
|
|
||||||
|
export namespace rutile
|
||||||
|
{
|
||||||
|
class BaseScene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Always define virtual destructor in abstract classes
|
||||||
|
virtual ~BaseScene() = default;
|
||||||
|
|
||||||
|
// Handle an SDL event. Return true if the event has been handled.
|
||||||
|
virtual bool handle_event(const sdl::Event& event) = 0;
|
||||||
|
|
||||||
|
// Update the scene
|
||||||
|
virtual void update() = 0;
|
||||||
|
|
||||||
|
// Render the scene
|
||||||
|
virtual void render(const RenderServer& render_server) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
26
src/rutile/core/scenes/scene_manager.cppm
Normal file
26
src/rutile/core/scenes/scene_manager.cppm
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
module;
|
||||||
|
|
||||||
|
export module rutile.core.scenes.scene_manager;
|
||||||
|
|
||||||
|
import rutile.core.scenes.base_scene;
|
||||||
|
|
||||||
|
export namespace rutile
|
||||||
|
{
|
||||||
|
class SceneManager
|
||||||
|
{
|
||||||
|
// Pointer to current scene
|
||||||
|
// TODO: Ownership? Should this be a regular pointer or maybe a shared_ptr shared with Game?
|
||||||
|
BaseScene* current_scene_ = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BaseScene* get_current_scene() const
|
||||||
|
{
|
||||||
|
return current_scene_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_current_scene(BaseScene& scene)
|
||||||
|
{
|
||||||
|
current_scene_ = &scene;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -5,13 +5,12 @@ module;
|
||||||
export module rutile.game.game;
|
export module rutile.game.game;
|
||||||
|
|
||||||
import std;
|
import std;
|
||||||
import rutile.core.drawing.sprite;
|
|
||||||
import rutile.core.drawing.tile_map;
|
|
||||||
import rutile.core.engine;
|
import rutile.core.engine;
|
||||||
import rutile.core.render_server;
|
import rutile.core.render_server;
|
||||||
|
import rutile.core.scenes.base_scene;
|
||||||
|
import rutile.game.scenes.game_scene;
|
||||||
import wrappers.rmlui.core;
|
import wrappers.rmlui.core;
|
||||||
import wrappers.sdl;
|
import wrappers.sdl;
|
||||||
import wrappers.sdl_image;
|
|
||||||
|
|
||||||
export namespace rutile
|
export namespace rutile
|
||||||
{
|
{
|
||||||
|
|
@ -23,26 +22,12 @@ export namespace rutile
|
||||||
// Reference to the engine
|
// Reference to the engine
|
||||||
Engine& engine_;
|
Engine& engine_;
|
||||||
|
|
||||||
// Sprites and stuff for testing
|
// Main game scene
|
||||||
Sprite player_sprite_;
|
GameScene game_scene_;
|
||||||
std::vector<Sprite> sprites_;
|
|
||||||
TileMap tile_map_;
|
|
||||||
|
|
||||||
// Private constructor
|
// Private constructor
|
||||||
explicit Game(Engine& engine)
|
explicit Game(Engine& engine)
|
||||||
: engine_(engine),
|
: engine_{engine}
|
||||||
player_sprite_{
|
|
||||||
Sprite::create_from_texture(
|
|
||||||
engine_.get_resource_server().load_texture("assets/sprites/neocat_64.png"),
|
|
||||||
std::nullopt,
|
|
||||||
sdl::FPoint{0, 0},
|
|
||||||
sdl::FPoint{-32, -32}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
tile_map_{
|
|
||||||
engine_.get_resource_server().load_tile_set("assets/tilesets/terrain.json"),
|
|
||||||
32, 16, 12, {50, 50}
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
// Initialize UI
|
// Initialize UI
|
||||||
const auto& ui_server = engine_.get_ui_server();
|
const auto& ui_server = engine_.get_ui_server();
|
||||||
|
|
@ -50,13 +35,8 @@ export namespace rutile
|
||||||
Rml::ElementDocument* document = ui_server.load_document("assets/ui/main_ui.rml");
|
Rml::ElementDocument* document = ui_server.load_document("assets/ui/main_ui.rml");
|
||||||
document->Show();
|
document->Show();
|
||||||
|
|
||||||
// Initialize tile map with example data
|
// Set current scene
|
||||||
for (auto x = 0; x < 10; x++) {
|
engine_.get_scene_manager().set_current_scene(game_scene_);
|
||||||
for (auto y = 0; y < 10; y++) {
|
|
||||||
const auto tile_index = 2 + (x + y) % 2;
|
|
||||||
tile_map_.set_tile(x, y, tile_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instantiated_ = true;
|
instantiated_ = true;
|
||||||
}
|
}
|
||||||
|
|
@ -84,55 +64,6 @@ export namespace rutile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles an SDL event. Returns true if the event has been handled.
|
|
||||||
bool handle_event(const sdl::Event& event)
|
|
||||||
{
|
|
||||||
if (event.type == sdl::EventTypes::MouseMotion) {
|
|
||||||
player_sprite_.set_position({event.motion.x, event.motion.y});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type == sdl::EventTypes::MouseButtonUp) {
|
|
||||||
sprites_.push_back(
|
|
||||||
Sprite::create_from_texture(
|
|
||||||
engine_.get_resource_server().load_texture("assets/sprites/neofox_64.png"),
|
|
||||||
std::nullopt,
|
|
||||||
sdl::FPoint{event.motion.x, event.motion.y},
|
|
||||||
sdl::FPoint{-32, -32}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update()
|
|
||||||
{
|
|
||||||
// TODO: Move this to Engine
|
|
||||||
engine_.get_ui_server().update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void render() const
|
|
||||||
{
|
|
||||||
const auto& render_server = engine_.get_render_server();
|
|
||||||
render_server.start_frame();
|
|
||||||
|
|
||||||
// Render tilemap
|
|
||||||
tile_map_.draw(render_server);
|
|
||||||
|
|
||||||
// Render sprites
|
|
||||||
for (const Sprite& sprite : sprites_) {
|
|
||||||
sprite.draw(render_server);
|
|
||||||
}
|
|
||||||
player_sprite_.draw(render_server);
|
|
||||||
|
|
||||||
// TODO: Move this to Engine
|
|
||||||
engine_.get_ui_server().render();
|
|
||||||
|
|
||||||
render_server.finish_frame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void shutdown()
|
void shutdown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
85
src/rutile/game/scenes/game_scene.cppm
Normal file
85
src/rutile/game/scenes/game_scene.cppm
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
module;
|
||||||
|
|
||||||
|
export module rutile.game.scenes.game_scene;
|
||||||
|
|
||||||
|
import std;
|
||||||
|
import rutile.core.drawing.sprite;
|
||||||
|
import rutile.core.drawing.tile_map;
|
||||||
|
import rutile.core.engine;
|
||||||
|
import rutile.core.render_server;
|
||||||
|
import rutile.core.scenes.base_scene;
|
||||||
|
import wrappers.sdl;
|
||||||
|
|
||||||
|
export namespace rutile
|
||||||
|
{
|
||||||
|
class GameScene : public BaseScene
|
||||||
|
{
|
||||||
|
// Sprites and stuff for testing
|
||||||
|
Sprite player_sprite_;
|
||||||
|
std::vector<Sprite> sprites_;
|
||||||
|
TileMap tile_map_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GameScene()
|
||||||
|
: player_sprite_{
|
||||||
|
Sprite::create_from_texture(
|
||||||
|
Engine::get().get_resource_server().load_texture("assets/sprites/neocat_64.png"),
|
||||||
|
std::nullopt,
|
||||||
|
sdl::FPoint{0, 0},
|
||||||
|
sdl::FPoint{-32, -32}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
tile_map_{
|
||||||
|
Engine::get().get_resource_server().load_tile_set("assets/tilesets/terrain.json"),
|
||||||
|
32, 16, 12, {50, 50}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Initialize tile map with example data
|
||||||
|
for (auto x = 0; x < 10; x++) {
|
||||||
|
for (auto y = 0; y < 10; y++) {
|
||||||
|
const auto tile_index = 2 + (x + y) % 2;
|
||||||
|
tile_map_.set_tile(x, y, tile_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles an SDL event. Returns true if the event has been handled.
|
||||||
|
bool handle_event(const sdl::Event& event) override
|
||||||
|
{
|
||||||
|
if (event.type == sdl::EventTypes::MouseMotion) {
|
||||||
|
player_sprite_.set_position({event.motion.x, event.motion.y});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == sdl::EventTypes::MouseButtonUp) {
|
||||||
|
sprites_.push_back(
|
||||||
|
Sprite::create_from_texture(
|
||||||
|
Engine::get().get_resource_server().load_texture("assets/sprites/neofox_64.png"),
|
||||||
|
std::nullopt,
|
||||||
|
sdl::FPoint{event.motion.x, event.motion.y},
|
||||||
|
sdl::FPoint{-32, -32}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(const RenderServer& render_server) override
|
||||||
|
{
|
||||||
|
// Render tilemap
|
||||||
|
tile_map_.draw(render_server);
|
||||||
|
|
||||||
|
// Render sprites
|
||||||
|
for (const Sprite& sprite : sprites_) {
|
||||||
|
sprite.draw(render_server);
|
||||||
|
}
|
||||||
|
player_sprite_.draw(render_server);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue