diff --git a/CMakeLists.txt b/CMakeLists.txt index df7932b..517d268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,8 @@ include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) # Includes the contents of th conan_basic_setup() # Prepares the CMakeList.txt for Conan. # $source_files is a space-delimited list of filenames. -add_executable(rla_iipp src/main.cpp src/engine/engine.hpp src/engine/game/game.hpp src/engine/rendering/renderer.hpp src/game/visualizer.hpp src/game/visualizer.cpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/engine.cpp src/engine/engine.hpp src/engine/rendering/sdl/sdltexturemanager.cpp src/engine/rendering/sdl/sdltexturemanager.hpp src/engine/resources/resourcemanager.hpp src/engine/rendering/sdl/sdlfontmanager.cpp src/engine/rendering/sdl/sdlfontmanager.hpp src/engine/input/inputprocessor.hpp src/engine/input/sdlinputprocessor.cpp src/engine/input/sdlinputprocessor.hpp src/engine/utility/camera.cpp src/engine/utility/camera.hpp src/engine/utility/point.hpp src/engine/utility/rectangle.hpp src/engine/utility/grid2d.hpp src/engine/scripting/luacontextmanager.cpp src/engine/scripting/luacontextmanager.hpp src/game/dungeonalgorithm.hpp) # Specifies the executable to build. +add_executable(rla_iipp src/main.cpp src/engine/engine.hpp src/engine/game/game.hpp src/engine/rendering/renderer.hpp src/game/visualizer.hpp src/game/visualizer.cpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/rendering/sdl/sdlrenderer.cpp src/engine/rendering/sdl/sdlrenderer.hpp src/engine/engine.cpp src/engine/engine.hpp src/engine/rendering/sdl/sdltexturemanager.cpp src/engine/rendering/sdl/sdltexturemanager.hpp src/engine/resources/resourcemanager.hpp src/engine/rendering/sdl/sdlfontmanager.cpp src/engine/rendering/sdl/sdlfontmanager.hpp src/engine/input/inputprocessor.hpp src/engine/input/sdlinputprocessor.cpp src/engine/input/sdlinputprocessor.hpp src/engine/utility/camera.cpp src/engine/utility/camera.hpp src/engine/utility/point.hpp src/engine/utility/rectangle.hpp src/engine/utility/grid2d.hpp src/engine/scripting/luacontextmanager.cpp src/engine/scripting/luacontextmanager.hpp src/game/algorithmmanager.cpp src/game/algorithmmanager.hpp src/game/tilemap.cpp src/game/tilemap.hpp src/engine/rlengineexception.hpp) # Specifies the executable to build. target_link_libraries(rla_iipp ${CONAN_LIBS}) # Specifies what libraries to link, using Conan. file(COPY assets DESTINATION ${CMAKE_BINARY_DIR}/bin) -file(COPY config DESTINATION ${CMAKE_BINARY_DIR}/bin) \ No newline at end of file +file(COPY config DESTINATION ${CMAKE_BINARY_DIR}/bin) +file(COPY scripts DESTINATION ${CMAKE_BINARY_DIR}/bin) \ No newline at end of file diff --git a/config/visualizer.toml b/config/visualizer.toml new file mode 100644 index 0000000..8b8dd9a --- /dev/null +++ b/config/visualizer.toml @@ -0,0 +1,9 @@ +[rendering] +tile_size_w = 48 +tile_size_h = 48 + +[map] +map_size_w = 20 +map_size_h = 20 +floor_char = '.' +wall_char = '#' \ No newline at end of file diff --git a/documents/algorithms.txt b/documents/algorithms.txt index b2a8829..0e2e913 100644 --- a/documents/algorithms.txt +++ b/documents/algorithms.txt @@ -1,14 +1,27 @@ Dungeon generation algorithms are written in lua and dropped into scripting->algorithms. They are automatically parsed by the visualizer and assigned keys in the program to run them. -Algorithms are made up of a single lua file (possibly more with requires) with the following functions: +Algorithms are made up of a single lua file (possibly more with requires) with the following functionality: -initialize() -Initializes the algorithm and returns a structure/table with the following fields: -{ - updates_per_second: int // Number of times the algorithm's update function should be called per second. Minimum of 1, converted into frames per update with a minimum of 1. - free_data: table // Free table that the developer can store necessary state data in -} +Provided: -update(state) +global algorithm_manager.register_algorithm(name, init_function, update_function, updates_per_second) +Registers an algorithm with the program with a given name, init function, update function, and updates per second -The following functions are available to algorithms in either their update or initialize functions: +map.draw_floor(x, y) +Draws a floor on the map at a given x, y position +map.draw_wall(x, y) +draws a wall on the map at a given x, y position + +map.fill(bool wall) +Fills the map with either floors (false) or walls (true) + +map.is_wall(x, y) +returns true if map[x,y] is a wall, false otherwise + +Necessary: + +init_function(map_w, map_h) +Should initialize the function fresh with a given width and height. + +update(map) +Called updates_per_second times per second. Should calculate new map state and draw on the map as needed. The map will have the previous state retained. diff --git a/src/engine/game/game.hpp b/src/engine/game/game.hpp index 76a4003..430933a 100644 --- a/src/engine/game/game.hpp +++ b/src/engine/game/game.hpp @@ -18,6 +18,8 @@ public: virtual bool update(InputResult input) = 0; virtual void render(Renderer* renderer) = 0; virtual void initialize(GameInitArgs args)=0; + + virtual ~Game()=default; }; #endif //RLA_IIPP_GAME_HPP diff --git a/src/engine/input/inputprocessor.hpp b/src/engine/input/inputprocessor.hpp index 232801e..8c10446 100644 --- a/src/engine/input/inputprocessor.hpp +++ b/src/engine/input/inputprocessor.hpp @@ -269,6 +269,7 @@ struct InputResult { class InputProcessor { public: virtual InputResult process_input()=0; + virtual ~InputProcessor()=default; }; #endif //RLA_IIPP_INPUTPROCESSOR_HPP diff --git a/src/engine/input/sdlinputprocessor.hpp b/src/engine/input/sdlinputprocessor.hpp index 5d9a2fa..2814057 100644 --- a/src/engine/input/sdlinputprocessor.hpp +++ b/src/engine/input/sdlinputprocessor.hpp @@ -15,6 +15,8 @@ class SdlInputProcessor : public InputProcessor { public: SdlInputProcessor(); + ~SdlInputProcessor() override = default; + private: std::unordered_map keycode_map; InputProcessorKeycode get_keycode(SDL_Keycode keycode); diff --git a/src/engine/rendering/renderer.hpp b/src/engine/rendering/renderer.hpp index 4c91ba1..90d0f4d 100644 --- a/src/engine/rendering/renderer.hpp +++ b/src/engine/rendering/renderer.hpp @@ -22,6 +22,9 @@ public: }; #define COLOR_BLACK Color(0, 0, 0, 255) #define COLOR_WHITE Color(255, 255, 255, 255) +#define COLOR_RED Color(255, 0, 0, 255) +#define COLOR_GREEN Color(0, 255, 0, 255) +#define COLOR_BLUE Color(0, 0, 255, 255) struct SpriteSheet { std::string path; @@ -60,6 +63,8 @@ public: virtual void draw_point(int x, int y, Color color) = 0; virtual void draw_text(std::optional details, std::string text,int x, int y)=0; virtual void draw_sprite(Sprite sprite, int x, int y)=0; + + virtual ~Renderer() = default;; }; #endif //RLA_IIPP_RENDERER_HPP diff --git a/src/engine/rendering/sdl/sdlrenderer.cpp b/src/engine/rendering/sdl/sdlrenderer.cpp index e6e8be0..6c64e7b 100644 --- a/src/engine/rendering/sdl/sdlrenderer.cpp +++ b/src/engine/rendering/sdl/sdlrenderer.cpp @@ -55,6 +55,10 @@ void SdlRenderer::draw_text(std::optional details, std::strin } SdlRenderer::~SdlRenderer() { + // clear resource managers pointing to shared pointers + // This avoids an invalid read, since otherwise TTF_Quit will cleanup fonts and then clearing the shared pointers will try it again + font_manager->clear_all_resources(); + texture_manager->clear_all_resources(); // exit subsystems IMG_Quit(); TTF_Quit(); diff --git a/src/engine/rendering/sdl/sdlrenderer.hpp b/src/engine/rendering/sdl/sdlrenderer.hpp index ade2831..ff351a9 100644 --- a/src/engine/rendering/sdl/sdlrenderer.hpp +++ b/src/engine/rendering/sdl/sdlrenderer.hpp @@ -17,7 +17,7 @@ struct SDL_WindowDeleter { class SdlRenderer : public Renderer { public: - ~SdlRenderer(); + ~SdlRenderer() override; void draw_text(std::optional details, std::string text, int x, int y) override; void initialize(RendererParams params) override; void flush() override; diff --git a/src/engine/rendering/sdl/sdltexturemanager.cpp b/src/engine/rendering/sdl/sdltexturemanager.cpp index 0c93ff5..b06bb95 100644 --- a/src/engine/rendering/sdl/sdltexturemanager.cpp +++ b/src/engine/rendering/sdl/sdltexturemanager.cpp @@ -27,7 +27,7 @@ std::shared_ptr SdlTextureManager::load_resource(TextureManagerFetc if(texture == nullptr) { throw MissingTextureException(full_path, SDL_GetError()); } - return std::shared_ptr(texture, SDL_DestroyTexture); + return {texture, SDL_DestroyTexture}; } std::string SdlTextureManager::get_key(TextureManagerFetchArgs args) { diff --git a/src/engine/resources/resourcemanager.hpp b/src/engine/resources/resourcemanager.hpp index 78e4221..4ef6a95 100644 --- a/src/engine/resources/resourcemanager.hpp +++ b/src/engine/resources/resourcemanager.hpp @@ -24,6 +24,9 @@ public: this->resource_map.erase(key); } } + virtual void clear_all_resources() { + this->resource_map.clear(); + } protected: std::unordered_map resource_map; diff --git a/src/engine/rlengineexception.hpp b/src/engine/rlengineexception.hpp new file mode 100644 index 0000000..6daed72 --- /dev/null +++ b/src/engine/rlengineexception.hpp @@ -0,0 +1,27 @@ +// +// Created by m on 12/20/21. +// + +#ifndef RLA_IIPP_RLENGINEEXCEPTION_HPP +#define RLA_IIPP_RLENGINEEXCEPTION_HPP + + +#include +#include +#include + +class RLEngineException : public std::exception { +public: + [[nodiscard]] const char *what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override { + return message.c_str(); + } + + explicit RLEngineException(std::string message) : message(std::move(message)) {} + +private: + std::string message; + +}; + + +#endif //RLA_IIPP_RLENGINEEXCEPTION_HPP diff --git a/src/engine/scripting/luacontextmanager.cpp b/src/engine/scripting/luacontextmanager.cpp index 4a30fb8..759a5a8 100644 --- a/src/engine/scripting/luacontextmanager.cpp +++ b/src/engine/scripting/luacontextmanager.cpp @@ -8,6 +8,7 @@ std::string LuaContextManager::get_key(std::string args) { return args; } +// TODO: Switch the arg to a struct and use that to init libraries std::shared_ptr LuaContextManager::load_resource(std::string args) { auto lua = std::make_shared(); lua->open_libraries(sol::lib::base, sol::lib::package); diff --git a/src/engine/scripting/luacontextmanager.hpp b/src/engine/scripting/luacontextmanager.hpp index 80d17df..b841e62 100644 --- a/src/engine/scripting/luacontextmanager.hpp +++ b/src/engine/scripting/luacontextmanager.hpp @@ -6,7 +6,6 @@ #define RLA_IIPP_LUACONTEXTMANAGER_HPP #include #include "../resources/resourcemanager.hpp" -#define DEFAULT_CONTEXT_KEY "default" class LuaContextManager : public ResourceManager, std::string, std::string> { @@ -21,6 +20,8 @@ protected: std::string get_key(std::string args) override; std::shared_ptr load_resource(std::string args) override; +private: + const std::string DEFAULT_CONTEXT_KEY = "default"; }; diff --git a/src/engine/utility/grid2d.hpp b/src/engine/utility/grid2d.hpp index e7b96e9..f00eaa4 100644 --- a/src/engine/utility/grid2d.hpp +++ b/src/engine/utility/grid2d.hpp @@ -8,6 +8,7 @@ #include #include +#include "point.hpp" template class Grid2D { private: diff --git a/src/game/algorithmmanager.cpp b/src/game/algorithmmanager.cpp new file mode 100644 index 0000000..e3cceb1 --- /dev/null +++ b/src/game/algorithmmanager.cpp @@ -0,0 +1,24 @@ +// +// Created by m on 12/13/21. +// + +#include "algorithmmanager.hpp" + +#include + +void AlgorithmManager::register_algorithm(std::string name, sol::function initialize, sol::function update, + unsigned int updates_per_second) { + unsigned int frames_per_update = target_fps / updates_per_second; + DungeonAlgorithm algorithm = { + frames_per_update, + std::move(update), + std::move(initialize), + std::move(name) + }; + algorithms.push_back(algorithm); + +} + +ranges::any_view AlgorithmManager::get_algorithms() { + return algorithms; +} diff --git a/src/game/algorithmmanager.hpp b/src/game/algorithmmanager.hpp new file mode 100644 index 0000000..044c4c9 --- /dev/null +++ b/src/game/algorithmmanager.hpp @@ -0,0 +1,35 @@ +// +// Created by m on 12/13/21. +// + +#ifndef RLA_IIPP_ALGORITHMMANAGER_HPP +#define RLA_IIPP_ALGORITHMMANAGER_HPP +#include +#include +struct DungeonAlgorithm { + unsigned int frames_per_update=1; + sol::function update; + sol::function initialize; + std::string name; +}; + +class AlgorithmManager { +private: + std::vector algorithms; + unsigned int target_fps=1; +public: + void register_algorithm(std::string name, sol::function initialize, sol::function update, unsigned int updates_per_second); + + void setTargetFps(unsigned int targetFps) { + target_fps = targetFps; + } + + ranges::any_view get_algorithms(); + + explicit AlgorithmManager(unsigned int targetFps) : target_fps(targetFps) {} + + AlgorithmManager() = default; +}; + + +#endif //RLA_IIPP_ALGORITHMMANAGER_HPP diff --git a/src/game/dungeonalgorithm.hpp b/src/game/dungeonalgorithm.hpp deleted file mode 100644 index b68a53b..0000000 --- a/src/game/dungeonalgorithm.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by m on 12/12/21. -// - -#ifndef RLA_IIPP_DUNGEONALGORITHM_HPP -#define RLA_IIPP_DUNGEONALGORITHM_HPP - -#include -#include -#include - -struct DungeonAlgorithm { - std::string path; - std::optional algorithm_data; - const int frames_per_update; - int frames_until_update=0; -}; - -#endif //RLA_IIPP_DUNGEONALGORITHM_HPP diff --git a/src/game/tilemap.cpp b/src/game/tilemap.cpp new file mode 100644 index 0000000..e3582ee --- /dev/null +++ b/src/game/tilemap.cpp @@ -0,0 +1,42 @@ +// +// Created by m on 12/14/21. +// + +#include "tilemap.hpp" +#include "../engine/utility/point.hpp" + +void TileMap::draw_floor(int x, int y) { + grid.insert(x, y, floor_tile); +} + +void TileMap::draw_wall(int x, int y) { + grid.insert(x, y, wall_tile); +} + +char TileMap::get_tile(int x, int y) { + return grid.get(x, y); +} + +void TileMap::fill(bool wall) { + for(Point p : grid.get_range()) { + if(wall) { + draw_wall(p.x, p.y); + } + else { + draw_floor(p.x, p.y); + } + } + +} + +bool TileMap::is_wall(int x, int y) { + return get_tile(x, y) == wall_tile; +} + +int TileMap::get_width() { + return grid.get_width(); +} + +int TileMap::get_height() { + return grid.get_height(); +} diff --git a/src/game/tilemap.hpp b/src/game/tilemap.hpp new file mode 100644 index 0000000..de01ed1 --- /dev/null +++ b/src/game/tilemap.hpp @@ -0,0 +1,34 @@ +// +// Created by m on 12/14/21. +// + +#ifndef RLA_IIPP_TILEMAP_HPP +#define RLA_IIPP_TILEMAP_HPP + + +#include "../engine/utility/grid2d.hpp" + +class TileMap { +private: + Grid2D grid = Grid2D(0, 0); + char wall_tile; + char floor_tile; +public: + void draw_floor(int x, int y); + void draw_wall(int x, int y); + void fill(bool wall); + char get_tile(int x, int y); + bool is_wall(int x, int y); + int get_width(); + int get_height(); + + TileMap(int width, int height, char wall_tile, char floor_tile) { + this->grid = Grid2D(width, height); + this->wall_tile = wall_tile; + this->floor_tile = floor_tile; + } + +}; + + +#endif //RLA_IIPP_TILEMAP_HPP diff --git a/src/game/visualizer.cpp b/src/game/visualizer.cpp index ecebb1a..a9d9d2e 100644 --- a/src/game/visualizer.cpp +++ b/src/game/visualizer.cpp @@ -3,6 +3,7 @@ // #include "visualizer.hpp" +#include "tilemap.hpp" bool Visualizer::update(InputResult input) { if(input.keycode == KEY_ESCAPE) { @@ -20,20 +21,13 @@ bool Visualizer::update(InputResult input) { this->y = std::clamp(this->y, 0, (int)this->tile_map.get_height()-1); this->camera.move_camera(Point{x,y}); - if(current_algorithm.has_value()) { - current_algorithm->frames_until_update -= 1; - if(current_algorithm->frames_until_update <= 0) { - update_algorithm(current_algorithm.value()); - current_algorithm->frames_until_update = current_algorithm->frames_per_update; - } - } return false; } void Visualizer::render(Renderer *renderer) { - SpriteSheet tiles = SpriteSheet{"sprites/map1.bmp", TILE_WIDTH, TILE_HEIGHT}; - SpriteSheet characters = SpriteSheet{"sprites/character.bmp", TILE_WIDTH, TILE_HEIGHT, COLOR_BLACK}; + SpriteSheet tiles = SpriteSheet{"sprites/map1.bmp", tile_width, tile_height}; + SpriteSheet characters = SpriteSheet{"sprites/character.bmp", tile_width, tile_height, COLOR_BLACK}; auto grass = Sprite{&tiles, 0}; auto wall = Sprite{&tiles, 497}; auto character = Sprite{&characters, this->sprite_index}; @@ -41,41 +35,60 @@ void Visualizer::render(Renderer *renderer) { for(Point p : camera.get_range()) { auto wp = camera.camera_coords_to_screen_coords(p); int wx = wp.x, wy = wp.y; - if(this->tile_map.get(p.x, p.y) == FLOOR_CHAR) { - renderer->draw_sprite(grass, wx*TILE_WIDTH, wy*TILE_HEIGHT); + if(this->tile_map.get_tile(p.x, p.y) == floor_char) { + renderer->draw_sprite(grass, wx*tile_width, wy*tile_height); } else { - renderer->draw_sprite(wall, wx*TILE_WIDTH, wy*TILE_HEIGHT); + renderer->draw_sprite(wall, wx*tile_width, wy*tile_height); } if(p.x == x && p.y == y) { - renderer->draw_sprite(character, wx*TILE_WIDTH, wy*TILE_HEIGHT); + renderer->draw_sprite(character, wx*tile_width, wy*tile_height); } } - return; // for breaking } void Visualizer::initialize(GameInitArgs args) { this->window_width = args.window_width; this->window_height = args.window_height; - int tilesx = (window_width / TILE_WIDTH)+1; - int tilesy = (window_height / TILE_HEIGHT)+1; - initialize_map(MAP_SIZE_W, MAP_SIZE_H); + Engine::load_config(CONFIG_FILE, [this](toml::table table) { + this->tile_width = table["rendering"]["tile_size_w"].value_or(DEFAULT_TILE_WIDTH); + this->tile_height = table["rendering"]["tile_size_h"].value_or(DEFAULT_TILE_HEIGHT); + this->map_size_w = table["map"]["map_size_w"].value_or(DEFAULT_MAP_SIZE_W); + this->map_size_h = table["map"]["map_size_h"].value_or(DEFAULT_MAP_SIZE_H); + this->floor_char = table["map"]["floor_char"].value_or(DEFAULT_FLOOR_CHAR)[0]; + this->wall_char = table["map"]["wall_char"].value_or(DEFAULT_WALL_CHAR)[0]; + }); + int tilesx = (window_width / tile_width)+1; + int tilesy = (window_height / tile_height)+1; + initialize_map(map_size_w, map_size_h); this->camera = Camera(Point{x,y}, tilesx, tilesy, tile_map.get_width(), tile_map.get_height()); + this->algorithm_manager = AlgorithmManager(args.target_fps); + this->initialize_context(); + } void Visualizer::initialize_map(int width, int height) { - this->tile_map = Grid2D(width, height); + this->tile_map = TileMap(width, height, wall_char, floor_char); for(int ty=0;tytile_map.get_height();ty++) { for (int tx = 0; tx < tile_map.get_width(); tx++) { - this->tile_map.insert(tx, ty, FLOOR_CHAR); + this->tile_map.draw_floor(tx, ty); } } } -void Visualizer::update_algorithm(DungeonAlgorithm algorithm) { +void Visualizer::initialize_context() { + auto lua = lua_context_manager.get_default_context(); + auto tilemap_lua = lua->new_usertype("TileMap", sol::no_constructor); + tilemap_lua["draw_floor"] = &TileMap::draw_floor; + tilemap_lua["draw_wall"] = &TileMap::draw_wall; + tilemap_lua["fill"] = &TileMap::fill; + tilemap_lua["is_wall"] = &TileMap::is_wall; + + auto algo_manager_lua = lua->new_usertype("AlgorithmManager", sol::no_constructor); + algo_manager_lua["register_algorithm"] = &AlgorithmManager::register_algorithm; } Visualizer::~Visualizer() = default; diff --git a/src/game/visualizer.hpp b/src/game/visualizer.hpp index f750bf4..7342054 100644 --- a/src/game/visualizer.hpp +++ b/src/game/visualizer.hpp @@ -6,18 +6,20 @@ #include "../engine/utility/camera.hpp" #include "../engine/utility/grid2d.hpp" #include "../engine/scripting/luacontextmanager.hpp" -#include "dungeonalgorithm.hpp" +#include "algorithmmanager.hpp" +#include "tilemap.hpp" #include #include #include #ifndef RLA_IIPP_VISUALIZER_HPP #define RLA_IIPP_VISUALIZER_HPP -#define MAP_SIZE_W 20 -#define MAP_SIZE_H 20 -#define TILE_WIDTH 48 -#define TILE_HEIGHT 48 -#define WALL_CHAR '#' -#define FLOOR_CHAR '.' +#define DEFAULT_MAP_SIZE_W 20 +#define DEFAULT_MAP_SIZE_H 20 +#define DEFAULT_TILE_WIDTH 48 +#define DEFAULT_TILE_HEIGHT 48 +#define DEFAULT_WALL_CHAR "#" +#define DEFAULT_FLOOR_CHAR "." +#define CONFIG_FILE "visualizer.toml" class Visualizer : public Game { public: @@ -34,17 +36,24 @@ public: private: int window_width = 0; int window_height = 0; - Grid2D tile_map = Grid2D(0, 0); + TileMap tile_map = TileMap(0, 0, DEFAULT_WALL_CHAR[0], DEFAULT_FLOOR_CHAR[0]); Camera camera = Camera(); LuaContextManager lua_context_manager = LuaContextManager(); - std::optional current_algorithm; + AlgorithmManager algorithm_manager; int x = 0; int y=0; int sprite_index = 1; + char floor_char; + char wall_char; + int map_size_w; + int map_size_h; + int tile_width; + int tile_height; + void initialize_map(int width, int height); - void update_algorithm(DungeonAlgorithm algorithm); + void initialize_context(); }; diff --git a/src/main.cpp b/src/main.cpp index 8084daa..717977d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,7 @@ int main() { std::unique_ptr renderer = std::make_unique(); std::unique_ptr game = std::make_unique(); std::unique_ptr input_processor = std::make_unique(); - auto* engine = new Engine(std::move(game), std::move(renderer), std::move(input_processor)); + auto engine = std::make_unique(std::move(game), std::move(renderer), std::move(input_processor)); engine->start_loop(); return 0;