diff --git a/.gitmodules b/.gitmodules index 6dd82fa..9f871ba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,3 +17,6 @@ path = docs/doxygen-awesome-css url = https://github.com/jothepro/doxygen-awesome-css.git +[submodule "extern/nlohmann_json"] + path = extern/nlohmann_json + url = https://github.com/nlohmann/json.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d38fa27..2b44666 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,10 +24,13 @@ add_subdirectory(extern/SDL_image EXCLUDE_FROM_ALL) add_subdirectory(extern/SDL_mixer EXCLUDE_FROM_ALL) add_subdirectory(extern/SDL_ttf EXCLUDE_FROM_ALL) add_subdirectory(extern/tmxlite/tmxlite EXCLUDE_FROM_ALL) +include_directories(extern/nlohmann_json/include) file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) -add_library(${PROJECT_NAME} ${SOURCES}) +add_library(${PROJECT_NAME} ${SOURCES} + include/ConfigLoader.h + src/ConfigLoader.cpp) target_include_directories(${PROJECT_NAME} PUBLIC ${ENGINE_INCLUDE_DIR}) diff --git a/config.json b/config.json new file mode 100644 index 0000000..0e0eb80 --- /dev/null +++ b/config.json @@ -0,0 +1,7 @@ +{ + "fullscreen": false, + "title": "VGG (Very Good Game)", + "height": 100, + "width": 100, + "icon": "./engine/internalAssets/iconImage.bmp" +} \ No newline at end of file diff --git a/extern/nlohmann_json b/extern/nlohmann_json new file mode 160000 index 0000000..a006a7a --- /dev/null +++ b/extern/nlohmann_json @@ -0,0 +1 @@ +Subproject commit a006a7a48bb30a247f0344b788c62c2806edd90b diff --git a/include/ConfigLoader.h b/include/ConfigLoader.h new file mode 100644 index 0000000..8ba9c55 --- /dev/null +++ b/include/ConfigLoader.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +using json = nlohmann::json; + +class ConfigLoader { + +public: + ConfigLoader(); + ~ConfigLoader(); + + void init(); + + void setCustomConfig(const std::optional& path); + + json getFinalConfig(); + +private: + json baseConfig; + std::optional customConfig; + json finalConfig; + + json loadConfigFromJSON(const std::string& path); + json mergeConfigs(json baseConfig, json customConfig); // getConfigFilePath() {return std::nullopt;} GameInternal* gameInternal; //!< \deprecated }; diff --git a/include/GameInternal.h b/include/GameInternal.h index 7cb3b1f..3850b43 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -11,6 +11,7 @@ #include "Vector2D.h" #include "Entity.h" #include "RenderManager.h" +#include "ConfigLoader.h" typedef std::function gamefunction; @@ -27,7 +28,7 @@ public: GameInternal(); ~GameInternal(); - SDL_AppResult init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen); + SDL_AppResult init(); void handleEvents(); void update(Uint64 frameTime); @@ -48,6 +49,8 @@ public: RenderManager renderManager; Map* map; // game specific, might not be needed for all types of games + ConfigLoader* config; + std::vector& tiles; std::vector& players; std::vector& projectiles; diff --git a/internalAssets/iconImage.bmp b/internalAssets/iconImage.bmp new file mode 100644 index 0000000..6eddbef Binary files /dev/null and b/internalAssets/iconImage.bmp differ diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index ae8242a..553617a 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -14,6 +14,7 @@ #include "Vector2D.h" #include "PowerupComponent.h" #include +#include #include "Textures.h" @@ -76,8 +77,8 @@ Vector2D AssetManager::calculateSpawnPosition() { SDL_Rect spawnRect; spawnRect.h = spawnRect.w = 32; - spawnRect.x = rand() % (SCREEN_SIZE_WIDTH - spawnRect.w); - spawnRect.y = rand() % (SCREEN_SIZE_HEIGHT - spawnRect.h); + spawnRect.x = rand() % (VEGO_Game().config->getFinalConfig().at("width").get() - spawnRect.w); + spawnRect.y = rand() % (VEGO_Game().config->getFinalConfig().at("height").get() - spawnRect.h); conflict = false; for (auto cc : this->man->getGame()->collisionHandler->getColliders({ Entity::GroupLabel::MAPTILES })) { diff --git a/src/CollisionHandler.cpp b/src/CollisionHandler.cpp index 5821303..0177728 100644 --- a/src/CollisionHandler.cpp +++ b/src/CollisionHandler.cpp @@ -10,6 +10,7 @@ #include #include #include +#include IntersectionBitSet CollisionHandler::getIntersection(Entity* entityA, Entity* entityB, Vector2D posModA, Vector2D posModB) { @@ -66,20 +67,20 @@ IntersectionBitSet CollisionHandler::getIntersectionWithBounds(Entity* entity, V // all 4 directions and both sides to allow checking for fully out of bounds if (collider->x + posMod.x < 0 || - collider->x + posMod.x > SCREEN_SIZE_WIDTH) { + collider->x + posMod.x > VEGO_Game().config->getFinalConfig().at("width")) { intersections.set((size_t) Direction::LEFT); } if (collider->x + collider->w + posMod.x < 0 || - collider->x + collider->w + posMod.x > SCREEN_SIZE_WIDTH) + collider->x + collider->w + posMod.x > VEGO_Game().config->getFinalConfig().at("width")) intersections.set((size_t) Direction::RIGHT); if (collider->y + posMod.y < 0 || - collider->y + posMod.y > SCREEN_SIZE_HEIGHT) + collider->y + posMod.y > VEGO_Game().config->getFinalConfig().at("height")) intersections.set((size_t) Direction::UP); if (collider->y + collider->h + posMod.y < 0 || - collider->y + collider->h + posMod.y > SCREEN_SIZE_HEIGHT) + collider->y + collider->h + posMod.y > VEGO_Game().config->getFinalConfig().at("height")) intersections.set((size_t) Direction::DOWN); return intersections; diff --git a/src/ConfigLoader.cpp b/src/ConfigLoader.cpp new file mode 100644 index 0000000..65381f5 --- /dev/null +++ b/src/ConfigLoader.cpp @@ -0,0 +1,52 @@ +#include "ConfigLoader.h" + +#include + +ConfigLoader::ConfigLoader() { + //TODO: look into adaptive paths for better handling as this requires the implemented game + // to have ./engine in the root folder + baseConfig = loadConfigFromJSON("./engine/config.json"); +} + +ConfigLoader::~ConfigLoader() {} + +void ConfigLoader::init() { + if (!customConfig.has_value()) { + finalConfig = baseConfig; + return; + } + finalConfig = mergeConfigs(baseConfig, customConfig.value()); +} + +json ConfigLoader::loadConfigFromJSON(const std::string& path) { + std::ifstream config_file(path); + json config; + + if (!config_file.is_open()) { + throw std::runtime_error(std::string("Could not load config file at: " + path)); + } + + config_file >> config; + return config; +} + + +void ConfigLoader::setCustomConfig(const std::optional& path) { + if (path.has_value()) { + customConfig = loadConfigFromJSON(path.value()); + } +} + +json ConfigLoader::mergeConfigs(json baseConfig, json customConfig) { + for (auto& entry : customConfig.items()) { + baseConfig[entry.key()] = entry.value(); + } + return baseConfig; +} + +json ConfigLoader::getFinalConfig() { + return finalConfig; +} + + + diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 1e4eac3..3c55148 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -15,6 +15,8 @@ #include +#include "ConfigLoader.h" + GameInternal::GameInternal() : manager(this), renderManager(), @@ -27,15 +29,23 @@ GameInternal::GameInternal() : GameInternal::~GameInternal() = default; -SDL_AppResult GameInternal::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen) +SDL_AppResult GameInternal::init() { + config = new ConfigLoader; + + this->gameInstance = GameFactory::instance().create(this); + config->setCustomConfig(this->gameInstance->getConfigFilePath()); + config->init(); + + json finalConfig = config->getFinalConfig(); + GameInternal::assets = new AssetManager(&manager); GameInternal::textureManager = new TextureManager(&manager); GameInternal::soundManager = new SoundManager(); GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer? int flags = 0; - if (fullscreen) + if (finalConfig.at("fullscreen")) { flags = SDL_WINDOW_FULLSCREEN; } @@ -52,7 +62,7 @@ SDL_AppResult GameInternal::init(const char* title, int xpos, int ypos, int widt return SDL_APP_FAILURE; } - window = SDL_CreateWindow(title, width, height, flags); + window = SDL_CreateWindow(finalConfig.at("title").get().c_str(), finalConfig.at("width"), finalConfig.at("height"), flags); if (!window) { std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; @@ -62,7 +72,7 @@ SDL_AppResult GameInternal::init(const char* title, int xpos, int ypos, int widt // bad SDL_Surface* icon; - if((icon = SDL_LoadBMP("assets/iconImage.bmp"))) + if((icon = SDL_LoadBMP(finalConfig.at("icon").get().c_str()))) { SDL_SetWindowIcon(window, icon); } @@ -95,7 +105,6 @@ SDL_AppResult GameInternal::init(const char* title, int xpos, int ypos, int widt // loading music // assets->addMusic("background_music", "assets/sound/background_music.mp3"); - this->gameInstance = GameFactory::instance().create(this); this->gameInstance->init(); return SDL_APP_CONTINUE; diff --git a/src/_Init.cpp b/src/_Init.cpp index cb82136..d108b73 100644 --- a/src/_Init.cpp +++ b/src/_Init.cpp @@ -19,7 +19,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) { *appstate = vego::game = new GameInternal(); - return vego::game->init("No_Name_Chicken_Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_SIZE_WIDTH, SCREEN_SIZE_HEIGHT, false); + return vego::game->init(); } SDL_AppResult SDL_AppIterate(void *appstate) {