From 68079d027960bbe84efdee3625be7a7edd9aa5bc Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 13 Oct 2024 13:29:32 +0200 Subject: [PATCH 01/42] made texture_cache map private --- include/TextureManager.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/TextureManager.h b/include/TextureManager.h index 3e4f1c4..dcf88d2 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -17,11 +17,10 @@ class TextureManager } } - std::map texture_cache; - SDL_Texture* loadTexture(const char* fileName); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); private: Manager* manager; + std::map texture_cache; }; \ No newline at end of file From 65e00c231477cd7422222fb8d9cb0ed9433a0655 Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 15 Oct 2024 13:24:56 +0200 Subject: [PATCH 02/42] changed texture_cache map to use enums instead of string for keys and functions using said map --- include/AssetManager.h | 2 +- include/SpriteComponent.h | 10 ++++++---- include/TextureEnumBase.h | 3 +++ include/TextureManager.h | 7 +++++-- src/AssetManager.cpp | 9 ++++++--- src/GameInternal.cpp | 5 +++-- src/SpriteComponent.cpp | 14 +++++++------- src/TextureManager.cpp | 35 +++++++++++++++++++++++++---------- src/TileComponent.cpp | 2 ++ 9 files changed, 58 insertions(+), 29 deletions(-) create mode 100644 include/TextureEnumBase.h diff --git a/include/AssetManager.h b/include/AssetManager.h index 1d3c97a..ee4a447 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -24,7 +24,7 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner); + void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, TexturesEnum textureEnum, Entity* owner); void createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath); Vector2D calculateSpawnPosition(); diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index ed584a2..bbeac64 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -4,10 +4,12 @@ #include #include #include +#include #include "AnimationHandler.h" #include "Component.h" #include "Direction.h" +#include "TextureEnumBase.h" class TransformComponent; @@ -23,7 +25,7 @@ private: SDL_Texture* texture; SDL_Rect srcRect, destRect; - const char* texturePath; + TexturesEnum textureEnum; bool animated = false; uint8_t frames = 0; @@ -32,15 +34,15 @@ private: public: SpriteComponent() = default; - SpriteComponent(const char* path); + SpriteComponent(TexturesEnum textureEnum); SpriteComponent( - const char* path, + TexturesEnum textureEnum, bool isAnimated, std::map>* animationList, std::string defaultAnimation); ~SpriteComponent(); - void setTexture(const char* path); + void setTexture(TexturesEnum texture); void init() override; void update() override; diff --git a/include/TextureEnumBase.h b/include/TextureEnumBase.h new file mode 100644 index 0000000..0857f12 --- /dev/null +++ b/include/TextureEnumBase.h @@ -0,0 +1,3 @@ +#pragma once + +enum class TexturesEnum; \ No newline at end of file diff --git a/include/TextureManager.h b/include/TextureManager.h index dcf88d2..2cc9469 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -6,6 +6,7 @@ #include #include #include +#include "TextureEnumBase.h" class TextureManager { @@ -17,10 +18,12 @@ class TextureManager } } - SDL_Texture* loadTexture(const char* fileName); + void addSingleTexture(TexturesEnum texture, const char* filePath); + void addTextures(const std::map& textures); + SDL_Texture* loadTexture(TexturesEnum texture); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); private: Manager* manager; - std::map texture_cache; + std::map texture_cache; }; \ No newline at end of file diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index a772fe6..b2d960c 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -15,12 +15,15 @@ #include "PowerupComponent.h" #include +#include "TextureEnumBase.h" + AssetManager::AssetManager(Manager* manager) : man(manager) {} AssetManager::~AssetManager() {} +//seems to not be used anymore void AssetManager::addTexture(std::string id, const char* path) { - textures.emplace(id, this->man->getGame()->textureManager->loadTexture(path)); + //textures.emplace(id, this->man->getGame()->textureManager->loadTexture(path)); } void AssetManager::addSoundEffect(std::string id, const char* path) @@ -46,11 +49,11 @@ Mix_Music* AssetManager::getMusic(std::string id) return music.at(id); } -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner) { +void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, TexturesEnum textureEnum, Entity* owner) { auto& projectile(man->addEntity()); projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects - projectile.addComponent(texturePath); + projectile.addComponent(textureEnum); projectile.addComponent(range, speed, velocity, owner); projectile.addComponent("projectile", 0.6f); projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE); diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 0e7587b..29d1622 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -78,10 +78,11 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he } SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - SDL_Texture* backgroundTexture = GameInternal::textureManager->loadTexture("assets/startscreen.png"); + + //SDL_Texture* backgroundTexture = GameInternal::textureManager->loadTexture("assets/startscreen.png"); SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, backgroundTexture, NULL, NULL); + //SDL_RenderCopy(renderer, backgroundTexture, NULL, NULL); SDL_RenderPresent(renderer); if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 2c730cf..8ec85e9 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -12,13 +12,13 @@ #include "GameInternal.h" #include "Manager.h" -SpriteComponent::SpriteComponent(const char* path) +SpriteComponent::SpriteComponent(TexturesEnum textureEnum) { - this->texturePath = path; + this->textureEnum = textureEnum; } SpriteComponent::SpriteComponent( - const char* path, + TexturesEnum textureEnum, bool isAnimated, std::map>* animationMap, std::string defaultAnimation) @@ -29,19 +29,19 @@ SpriteComponent::SpriteComponent( playAnimation(defaultAnimation); - this->texturePath = path; + this->textureEnum = textureEnum; } SpriteComponent::~SpriteComponent() {} -void SpriteComponent::setTexture(const char* path) +void SpriteComponent::setTexture(TexturesEnum texture) { - this->texture = this->entity->getManager().getGame()->textureManager->loadTexture(path); + this->texture = this->entity->getManager().getGame()->textureManager->loadTexture(texture); } void SpriteComponent::init() { - setTexture(this->texturePath); + setTexture(this->textureEnum); this->transform = &entity->getComponent(); diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index 3e46d46..03852ad 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -6,17 +6,32 @@ #include "GameInternal.h" -SDL_Texture* TextureManager::loadTexture(const char* fileName) -{ - auto it = this->texture_cache.find(fileName); - if (it != this->texture_cache.end()) { - return it->second; + +void TextureManager::addSingleTexture(TexturesEnum texture, const char* filePath) { + auto sdlTexture = IMG_LoadTexture(this->manager->getGame()->renderer, filePath); + + if (sdlTexture == nullptr) + throw std::runtime_error(std::string("Couldn't load texture '") + filePath + "'"); + + this->texture_cache.emplace(texture, sdlTexture); + std::cout << "Loaded texture at " << filePath << std::endl; +} + +void TextureManager::addTextures(const std::map &textures) { + for (auto texture : textures) { + addSingleTexture(texture.first, texture.second); } - auto texture = IMG_LoadTexture(this->manager->getGame()->renderer, fileName); - if (texture == NULL) throw std::runtime_error(std::string("Couldn't load texture '") + fileName + "'"); - this->texture_cache.emplace(std::string(fileName), texture); - printf("Loaded texture at '%s'\n", fileName); - return texture; +} + + +SDL_Texture* TextureManager::loadTexture(TexturesEnum texture) { + auto it = this->texture_cache.find(texture); + + if (it != this->texture_cache.end()) + return it->second; + + std::cout << "ERROR: Couldn't load texture!" << std::endl; + return nullptr; } void TextureManager::draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped) diff --git a/src/TileComponent.cpp b/src/TileComponent.cpp index eeebb92..8658e93 100644 --- a/src/TileComponent.cpp +++ b/src/TileComponent.cpp @@ -7,6 +7,8 @@ #include "SpriteComponent.h" #include "TileComponent.h" +#include "TextureEnumBase.h" + TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict) { this->tileRect.x = x; From 9e346a719df5da7840170a3550f77c9bf5d87d80 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Fri, 15 Nov 2024 22:25:43 +0100 Subject: [PATCH 03/42] Reimplemented collision still missing documentation --- include/Map.h | 9 +++++++-- src/Map.cpp | 47 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/include/Map.h b/include/Map.h index 92b8179..ab784bb 100644 --- a/include/Map.h +++ b/include/Map.h @@ -1,8 +1,11 @@ #pragma once +#include +#include #include #include #include +#include class GameInternal; class Map @@ -32,5 +35,7 @@ public: */ static void loadMapTmx(const char* path); private: - static void addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath); -}; + static void addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath, bool hasCollision); + template + static std::optional getLayerProperty(const std::vector& properties, std::string propertyName) { return std::nullopt; }; +}; \ No newline at end of file diff --git a/src/Map.cpp b/src/Map.cpp index 1653c72..0fb735b 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include +#include "ColliderComponent.h" #include "Constants.h" #include "GameInternal.h" #include "SpriteComponent.h" @@ -81,6 +83,31 @@ void Map::addTile(unsigned long id, int x, int y, GameInternal* game, const std: tile.addGroup((size_t)Entity::GroupLabel::MAPTILES); } + +template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { + auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; + }); + + if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { + return zIndexIterator->getBoolValue(); + } + + return std::nullopt; +} + +template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { + auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; + }); + + if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { + return zIndexIterator->getIntValue(); + } + + return std::nullopt; +} + void Map::loadMapTmx(const char* path) { tmx::Map map; @@ -105,16 +132,11 @@ void Map::loadMapTmx(const char* path) if (layer->getType() == tmx::Layer::Type::Tile) { auto& tileLayer = layer->getLayerAs(); - int zIndex = 0; - const std::vector& properties = layer->getProperties(); - auto zIndexIterator = std::find_if(properties.begin(), properties.end(), [](const tmx::Property& property) { - return property.getName() == "zIndex"; - }); + int zIndex = getLayerProperty(properties, "zIndex").value_or(0); + bool collision = getLayerProperty(properties, "collision").value_or(false); - if (zIndexIterator != properties.end() && std::is_nothrow_convertiblegetType()), int>::value) { - zIndex = zIndexIterator->getIntValue(); - } + printf("z-index: %d, collision: %d\n", zIndex, collision); const auto& tiles = tileLayer.getTiles(); @@ -151,7 +173,7 @@ void Map::loadMapTmx(const char* path) const float tilePosX = static_cast(x) * mapTileSize.x; const float tilePosY = (static_cast(y) * mapTileSize.y); - Map::addTile(tilePosX, tilePosY, mapTileSize, u, v, zIndex, texturePaths.at(i).c_str()); + Map::addTile(tilePosX, tilePosY, mapTileSize, u, v, zIndex, texturePaths.at(i).c_str(), collision); } } if (layer->getType() == tmx::Layer::Type::Object) { @@ -162,10 +184,15 @@ void Map::loadMapTmx(const char* path) } } -void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath) +void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath, bool hasCollision) { auto& tile(VEGO_Game().manager.addEntity()); tile.addComponent(x, y, mapTileSize.x, mapTileSize.y, 1); tile.addComponent(texturePath, v, u, zIndex); // why does uv need to be reversed? + + if (hasCollision) { + tile.addComponent("hello I am a collider of a tile!"); + tile.addGroup((size_t)Entity::GroupLabel::MAPTILES); + } } \ No newline at end of file From 7f4b1df8338a32188f4339dc5ccc47643c6fbc8a Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sat, 16 Nov 2024 19:31:44 +0100 Subject: [PATCH 04/42] Restructured code --- CMakeLists.txt | 2 +- include/Map.h | 49 ++++++--- src/GameInternal.cpp | 2 - src/Map.cpp | 250 ++++++++++++++++++++----------------------- 4 files changed, 151 insertions(+), 152 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 602370b..e222a1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15) project(engine) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(ENGINE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/include/Map.h b/include/Map.h index ab784bb..ed9af33 100644 --- a/include/Map.h +++ b/include/Map.h @@ -1,5 +1,8 @@ #pragma once +#include "tmxlite/Map.hpp" +#include "tmxlite/TileLayer.hpp" +#include #include #include #include @@ -11,31 +14,45 @@ class GameInternal; class Map { public: - Map() = default; - ~Map() = default; + Map(const char* path); - /*! - * - * \brief - * This loads a map - * - * \param path The path to the map file - * \return Boolean for success - * - */ - [[deprecated("ID based text files are not supported anymore, use .txm maps instead")]] - static void loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */); - [[deprecated]] - static void addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict); + //[[deprecated("ID based text files are not supported anymore, use .tmx maps instead")]] + //static void loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */); + //[[deprecated]] + //static void addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict); /*! * \brief Loads a .tmx map * \param path Path to the `.tmx` map file * */ - static void loadMapTmx(const char* path); + + void generateTiles(); private: + // required for initialisation + struct MapData { + const std::vector* tileSets; + const std::vector* mapLayers; + const tmx::Vector2u* mapSize; + const tmx::Vector2u* mapTileSize; + const std::vector* texturePaths; + }; + + struct TileSetData { + const char* texturePath{}; + tmx::Vector2i textureSize; + uint32_t tileCount{}; + tmx::Vector2u tileCount2D; + uint32_t firstGID{}; + }; + + tmx::Map map; + Map::MapData mapData; + std::vector> tileConstructors; + + void loadTileLayer(const tmx::TileLayer& layer); static void addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath, bool hasCollision); + template static std::optional getLayerProperty(const std::vector& properties, std::string propertyName) { return std::nullopt; }; }; \ No newline at end of file diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index c5ba507..e32bb00 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -133,8 +133,6 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he if (this->isRunning() == false) return; - map = new Map(); - // loading sounds // assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav"); // assets->addSoundEffect("steps", "assets/sound/steps.wav"); diff --git a/src/Map.cpp b/src/Map.cpp index 0fb735b..975b83b 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -2,10 +2,14 @@ #include #include +#include #include +#include #include #include #include +#include +#include #include #include #include @@ -28,171 +32,151 @@ #include "VEGO.h" #include "tmxlite/Types.hpp" -void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */) -{ - std::string tileIDstr; - char singleChar = 0; - std::ifstream mapFile; - mapFile.open(path); - - if (!mapFile.is_open()) { - SDL_SetError("Error loading map: Couldn't open map file!"); - std::cout << "ERROR: Map couldnt be loaded! " << SDL_GetError() << std::endl; - SDL_ClearError(); - } - - int x = 0, y = 0; // needed outside for-loop for error handling - for (; !mapFile.eof(); mapFile.get(singleChar)) - { - if (singleChar == ',' || singleChar == '\n') { - if (tileIDstr.empty()) - continue; - Map::addTile(std::stoi(tileIDstr), x * TILE_SIZE, y * TILE_SIZE, game, textureDict); - tileIDstr.clear(); - x++; - if (singleChar == '\n') { - if (x != sizeX) { - SDL_SetError("Error loading map: specified x size doesn't match map file!"); - std::cout << "ERROR: Map couldnt be loaded! " << SDL_GetError() << std::endl; - SDL_ClearError(); - } - x = 0; - y++; - continue; - } - continue; - } - if (!std::isdigit(singleChar)) continue; - tileIDstr += singleChar; - } - if (y != sizeY) { - SDL_SetError("Error loading map: specified y size doesn't match map file!"); - std::cout << "ERROR: Map couldnt be loaded! " << SDL_GetError() << std::endl; - SDL_ClearError(); - } - - mapFile.close(); -} - -void Map::addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict) // tile entity -{ - auto& tile(game->manager.addEntity()); - tile.addComponent(x, y, TILE_SIZE, TILE_SIZE, id, textureDict); - - if(tile.getComponent().hasCollision()) tile.addComponent(tile.getComponent().getName().data()); - tile.addGroup((size_t)Entity::GroupLabel::MAPTILES); -} - - template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { - auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { - return property.getName().compare(propertyName) == 0; - }); +auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; +}); - if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { - return zIndexIterator->getBoolValue(); - } +if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { + return zIndexIterator->getBoolValue(); +} - return std::nullopt; +return std::nullopt; } template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { - auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { - return property.getName().compare(propertyName) == 0; - }); +auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; +}); - if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { - return zIndexIterator->getIntValue(); - } - - return std::nullopt; +if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { + return zIndexIterator->getIntValue(); } -void Map::loadMapTmx(const char* path) +return std::nullopt; +} + +Map::Map(const char* path) { - tmx::Map map; - if (!map.load(path)) { + if (!this->map.load(path)) { // TODO: log to console + // TODO: error handling } - const std::vector& tileSets = map.getTilesets(); - - const std::vector& mapLayers = map.getLayers(); - const auto mapSize = map.getTileCount(); - const auto mapTileSize = map.getTileSize(); - std::vector texturePaths = {}; - for (auto tileSet : tileSets) { + for (auto tileSet : map.getTilesets()) { texturePaths.emplace_back(tileSet.getImagePath()); } - for (auto& layer : mapLayers) { + this->mapData = { + &map.getTilesets(), + &map.getLayers(), + &map.getTileCount(), + &map.getTileSize(), + &texturePaths + }; + + + for (auto& layer : *this->mapData.mapLayers) { if (layer->getType() == tmx::Layer::Type::Tile) { - auto& tileLayer = layer->getLayerAs(); - - const std::vector& properties = layer->getProperties(); - int zIndex = getLayerProperty(properties, "zIndex").value_or(0); - bool collision = getLayerProperty(properties, "collision").value_or(false); - - printf("z-index: %d, collision: %d\n", zIndex, collision); - - const auto& tiles = tileLayer.getTiles(); - - for (auto i = 0u; i < tileSets.size(); i++) { - auto tilesetTexture = VEGO_Game().textureManager->loadTexture(texturePaths.at(i).c_str()); - tmx::Vector2i textureSize; - SDL_QueryTexture(tilesetTexture, nullptr, nullptr, &(textureSize.x), &(textureSize.y)); - - const auto tileCountX = textureSize.x / mapTileSize.x; - const auto tileCountY = textureSize.y / mapTileSize.y; - - for (auto idx = 0ul; idx < mapSize.x * mapSize.y; idx++) { - - if (idx >= tiles.size() || tiles[idx].ID < tileSets.at(i).getFirstGID() - || tiles[idx].ID >= (tileSets.at(i).getFirstGID() + tileSets.at(i).getTileCount())) { - continue; - } - - const auto x = idx % mapSize.x; - const auto y = idx / mapSize.x; - - auto idIndex = (tiles[idx].ID - tileSets.at(i).getFirstGID()); - - int u = idIndex % tileCountX; - int v = idIndex / tileCountY; - u *= mapTileSize.x; //TODO we should be using the tile set size, as this may be different from the map's grid size - v *= mapTileSize.y; - - //normalise the UV - u /= textureSize.x; - v /= textureSize.y; - - //vert pos - const float tilePosX = static_cast(x) * mapTileSize.x; - const float tilePosY = (static_cast(y) * mapTileSize.y); - - Map::addTile(tilePosX, tilePosY, mapTileSize, u, v, zIndex, texturePaths.at(i).c_str(), collision); - } - } - if (layer->getType() == tmx::Layer::Type::Object) { - // spawn objects - continue; - } + loadTileLayer(layer->getLayerAs()); + continue; + } + if (layer->getType() == tmx::Layer::Type::Object) { + // spawn objects + continue; } } } +void Map::loadTileLayer(const tmx::TileLayer& layer) +{ + const std::vector& properties = layer.getProperties(); + int zIndex = getLayerProperty(properties, "zIndex").value_or(0); + bool collision = getLayerProperty(properties, "collision").value_or(false); + + const auto& tiles = layer.getTiles(); + + auto tileConstructorRange = std::views::iota(0) + | std::views::take(this->mapData.tileSets->size()) + | std::views::transform([&](uint16_t i) { + const char* texturePath = this->mapData.texturePaths->at(i).c_str(); + + tmx::Vector2i textureSize; + SDL_QueryTexture( + VEGO_Game().textureManager->loadTexture(texturePath), + nullptr, + nullptr, + &(textureSize.x), + &(textureSize.y) + ); + + tmx::Vector2u tileCount2D = { textureSize.x / this->mapData.mapTileSize->x, textureSize.y / this->mapData.mapTileSize->y }; + + uint32_t tileCount = this->mapData.tileSets->at(i).getTileCount(); + uint32_t firstGID = this->mapData.tileSets->at(i).getFirstGID(); + + return TileSetData { texturePath, textureSize, tileCount, tileCount2D, firstGID }; + }) + | std::views::transform([=, this](const TileSetData& data) { + return std::views::iota(0) + | std::views::take(this->mapData.mapSize->x * this->mapData.mapSize->y) + | std::views::filter([=](uint16_t idx) { + return + idx < tiles.size() + && tiles[idx].ID >= data.firstGID + && tiles[idx].ID < (data.firstGID + data.tileCount); + }) + | std::views::transform([=, this](uint16_t idx) { + const auto x = idx % this->mapData.mapSize->x; + const auto y = idx / this->mapData.mapSize->x; + + const auto idIndex = (tiles[idx].ID - data.firstGID); + + uint32_t u = idIndex % data.tileCount2D.x; + uint32_t v = idIndex / data.tileCount2D.y; + u *= this->mapData.mapTileSize->x; // TODO: we should be using the tile set size, as this may be different from the map's grid size + v *= this->mapData.mapTileSize->y; + + // normalise the UV + u /= data.textureSize.x; + v /= data.textureSize.y; + + // vert pos + const float tilePosX = static_cast(x) * this->mapData.mapTileSize->x; + const float tilePosY = (static_cast(y) * this->mapData.mapTileSize->y); + + return std::function( + [tilePosX, tilePosY, capture0 = *this->mapData.mapTileSize, u, v, zIndex, capture1 = data.texturePath, collision] { + Map::addTile(tilePosX, tilePosY, capture0, u, v, zIndex, capture1, collision); + } + ); + }); + }) + | std::views::join + | std::ranges::to(); + + this->tileConstructors.insert(this->tileConstructors.end(), tileConstructorRange.begin(), tileConstructorRange.end()); +} + void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath, bool hasCollision) { auto& tile(VEGO_Game().manager.addEntity()); tile.addComponent(x, y, mapTileSize.x, mapTileSize.y, 1); - tile.addComponent(texturePath, v, u, zIndex); // why does uv need to be reversed? + tile.addComponent("assets/grassy-river-tiles.png" /*texturePath*/, v, u, zIndex); // why does uv need to be reversed? if (hasCollision) { tile.addComponent("hello I am a collider of a tile!"); tile.addGroup((size_t)Entity::GroupLabel::MAPTILES); } +} + +void Map::generateTiles() +{ + std::ranges::for_each(this->tileConstructors, [](auto& function) { + function(); + }); } \ No newline at end of file From 70260c01bbaf70755ecffeb7c7f9b55190056367 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sun, 17 Nov 2024 12:39:14 +0100 Subject: [PATCH 05/42] structural improvements & code comments --- include/Map.h | 72 ++++++++++++++++++++++++++++++++------------------- src/Map.cpp | 42 +++++++----------------------- 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/include/Map.h b/include/Map.h index ed9af33..3a6019a 100644 --- a/include/Map.h +++ b/include/Map.h @@ -1,50 +1,44 @@ #pragma once -#include "tmxlite/Map.hpp" -#include "tmxlite/TileLayer.hpp" #include -#include #include -#include -#include #include #include +#include +#include +#include +#include + class GameInternal; class Map { public: - Map(const char* path); - - //[[deprecated("ID based text files are not supported anymore, use .tmx maps instead")]] - //static void loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */); - //[[deprecated]] - //static void addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict); - /*! * \brief Loads a .tmx map + * \details Loads a `.tmx` file and extracts all relevant data. Any entities (including tiles) are only spawned once * \param path Path to the `.tmx` map file - * + * \sa Map::generateTiles() */ - - void generateTiles(); + Map(const char* path); + void generateTiles(); //!< Generates the map based on the loaded definition private: - // required for initialisation + // struct required for initialisation struct MapData { - const std::vector* tileSets; - const std::vector* mapLayers; - const tmx::Vector2u* mapSize; - const tmx::Vector2u* mapTileSize; - const std::vector* texturePaths; + const std::vector* tileSets; + const std::vector* mapLayers; + const tmx::Vector2u* mapSize; + const tmx::Vector2u* mapTileSize; + const std::vector* texturePaths; }; struct TileSetData { - const char* texturePath{}; - tmx::Vector2i textureSize; - uint32_t tileCount{}; - tmx::Vector2u tileCount2D; - uint32_t firstGID{}; - }; + const char* texturePath{}; + tmx::Vector2i textureSize; + uint32_t tileCount{}; + tmx::Vector2u tileCount2D; + uint32_t firstGID{}; + }; tmx::Map map; Map::MapData mapData; @@ -55,4 +49,28 @@ private: template static std::optional getLayerProperty(const std::vector& properties, std::string propertyName) { return std::nullopt; }; + template<> std::optional getLayerProperty(const std::vector& properties, std::string propertyName) { + auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; + }); + + if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { + return zIndexIterator->getBoolValue(); + } + + return std::nullopt; + } + + template<> std::optional getLayerProperty(const std::vector& properties, std::string propertyName) + { + auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; + }); + + if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { + return zIndexIterator->getIntValue(); + } + + return std::nullopt; + } }; \ No newline at end of file diff --git a/src/Map.cpp b/src/Map.cpp index 975b83b..e75db70 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -5,13 +5,8 @@ #include #include #include -#include -#include #include #include -#include -#include -#include #include #include @@ -22,39 +17,14 @@ #include #include #include +#include #include "ColliderComponent.h" -#include "Constants.h" #include "GameInternal.h" #include "SpriteComponent.h" #include "TextureManager.h" #include "TileComponent.h" #include "VEGO.h" -#include "tmxlite/Types.hpp" - -template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { -auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { - return property.getName().compare(propertyName) == 0; -}); - -if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { - return zIndexIterator->getBoolValue(); -} - -return std::nullopt; -} - -template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { -auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { - return property.getName().compare(propertyName) == 0; -}); - -if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { - return zIndexIterator->getIntValue(); -} - -return std::nullopt; -} Map::Map(const char* path) { @@ -65,7 +35,7 @@ Map::Map(const char* path) std::vector texturePaths = {}; - for (auto tileSet : map.getTilesets()) { + for (const auto& tileSet : map.getTilesets()) { texturePaths.emplace_back(tileSet.getImagePath()); } @@ -99,8 +69,10 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) const auto& tiles = layer.getTiles(); + // for each tile set auto tileConstructorRange = std::views::iota(0) | std::views::take(this->mapData.tileSets->size()) + // return the tile set metadata | std::views::transform([&](uint16_t i) { const char* texturePath = this->mapData.texturePaths->at(i).c_str(); @@ -121,14 +93,17 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) return TileSetData { texturePath, textureSize, tileCount, tileCount2D, firstGID }; }) | std::views::transform([=, this](const TileSetData& data) { + // for each tile on the tile set return std::views::iota(0) | std::views::take(this->mapData.mapSize->x * this->mapData.mapSize->y) + // only take tiles that are on the ID range of the tile set | std::views::filter([=](uint16_t idx) { return idx < tiles.size() && tiles[idx].ID >= data.firstGID && tiles[idx].ID < (data.firstGID + data.tileCount); }) + // extract tile data | std::views::transform([=, this](uint16_t idx) { const auto x = idx % this->mapData.mapSize->x; const auto y = idx / this->mapData.mapSize->x; @@ -148,6 +123,7 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) const float tilePosX = static_cast(x) * this->mapData.mapTileSize->x; const float tilePosY = (static_cast(y) * this->mapData.mapTileSize->y); + // return tile data as a function to spawn said tile return std::function( [tilePosX, tilePosY, capture0 = *this->mapData.mapTileSize, u, v, zIndex, capture1 = data.texturePath, collision] { Map::addTile(tilePosX, tilePosY, capture0, u, v, zIndex, capture1, collision); @@ -155,6 +131,7 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) ); }); }) + // 2D view to 1D vector; might be better keep as view with scene management | std::views::join | std::ranges::to(); @@ -169,6 +146,7 @@ void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int tile.addComponent("assets/grassy-river-tiles.png" /*texturePath*/, v, u, zIndex); // why does uv need to be reversed? if (hasCollision) { + // tag currently does not have a clear purposes, TODO: figure out appropriate tag name tile.addComponent("hello I am a collider of a tile!"); tile.addGroup((size_t)Entity::GroupLabel::MAPTILES); } From 92dfbacd9be1730929bedf5d50a4e42a6b6715e7 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sun, 17 Nov 2024 13:07:33 +0100 Subject: [PATCH 06/42] Fixed templates and const char* for texture --- include/Map.h | 28 ++-------------------------- src/Map.cpp | 30 ++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/include/Map.h b/include/Map.h index 3a6019a..244322e 100644 --- a/include/Map.h +++ b/include/Map.h @@ -33,7 +33,7 @@ private: }; struct TileSetData { - const char* texturePath{}; + std::string texturePath{}; tmx::Vector2i textureSize; uint32_t tileCount{}; tmx::Vector2u tileCount2D; @@ -45,32 +45,8 @@ private: std::vector> tileConstructors; void loadTileLayer(const tmx::TileLayer& layer); - static void addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath, bool hasCollision); + static void addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, std::string texturePath, bool hasCollision); template static std::optional getLayerProperty(const std::vector& properties, std::string propertyName) { return std::nullopt; }; - template<> std::optional getLayerProperty(const std::vector& properties, std::string propertyName) { - auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { - return property.getName().compare(propertyName) == 0; - }); - - if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { - return zIndexIterator->getBoolValue(); - } - - return std::nullopt; - } - - template<> std::optional getLayerProperty(const std::vector& properties, std::string propertyName) - { - auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { - return property.getName().compare(propertyName) == 0; - }); - - if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { - return zIndexIterator->getIntValue(); - } - - return std::nullopt; - } }; \ No newline at end of file diff --git a/src/Map.cpp b/src/Map.cpp index e75db70..dab109b 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -26,6 +26,32 @@ #include "TileComponent.h" #include "VEGO.h" + +template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { + auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; + }); + + if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Boolean) { + return zIndexIterator->getBoolValue(); + } + + return std::nullopt; +} + +template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) +{ + auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { + return property.getName().compare(propertyName) == 0; + }); + + if (zIndexIterator != properties.end() && zIndexIterator->getType() == tmx::Property::Type::Int) { + return zIndexIterator->getIntValue(); + } + + return std::nullopt; +} + Map::Map(const char* path) { if (!this->map.load(path)) { @@ -138,12 +164,12 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) this->tileConstructors.insert(this->tileConstructors.end(), tileConstructorRange.begin(), tileConstructorRange.end()); } -void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, const char* texturePath, bool hasCollision) +void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int v, int zIndex, std::string texturePath, bool hasCollision) { auto& tile(VEGO_Game().manager.addEntity()); tile.addComponent(x, y, mapTileSize.x, mapTileSize.y, 1); - tile.addComponent("assets/grassy-river-tiles.png" /*texturePath*/, v, u, zIndex); // why does uv need to be reversed? + tile.addComponent(texturePath.c_str(), v, u, zIndex); // why does uv need to be reversed? if (hasCollision) { // tag currently does not have a clear purposes, TODO: figure out appropriate tag name From 494ff8aa0a84557703976e618ed3fc6e7d7f4fd6 Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 17 Nov 2024 16:00:47 +0100 Subject: [PATCH 07/42] magic_enum library stuff and refactored TextureEnum to Textures due to bad naming --- .gitmodules | 3 +++ CMakeLists.txt | 2 ++ extern/magic_enum | 1 + include/AssetManager.h | 6 ++---- include/Map.h | 5 +++-- include/SpriteComponent.h | 9 ++++----- include/TextureEnumBase.h | 2 +- include/TextureManager.h | 8 ++++---- include/TileComponent.h | 22 +++++++++++++++++----- src/AssetManager.cpp | 11 +++-------- src/Map.cpp | 8 +++++--- src/SpriteComponent.cpp | 6 +++--- src/TextureManager.cpp | 6 +++--- src/TileComponent.cpp | 7 +++---- 14 files changed, 54 insertions(+), 42 deletions(-) create mode 160000 extern/magic_enum diff --git a/.gitmodules b/.gitmodules index bfa520c..3ae9513 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,3 +14,6 @@ path = extern/SDL_ttf url = https://github.com/libsdl-org/SDL_ttf.git branch = release-2.22.x +[submodule "extern/magic_enum"] + path = extern/magic_enum + url = https://github.com/Neargye/magic_enum.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 5149005..24a3f77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(extern/SDL EXCLUDE_FROM_ALL) 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/magic_enum EXCLUDE_FROM_ALL) file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) add_library(${PROJECT_NAME} ${SOURCES}) @@ -33,6 +34,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC # should be private when all SDL fu SDL2_image::SDL2_image-static SDL2_mixer::SDL2_mixer-static SDL2_ttf::SDL2_ttf-static + magic_enum::magic_enum ) if(CMAKE_BUILD_TYPE MATCHES "Debug") diff --git a/extern/magic_enum b/extern/magic_enum new file mode 160000 index 0000000..a72a053 --- /dev/null +++ b/extern/magic_enum @@ -0,0 +1 @@ +Subproject commit a72a0536c716fdef4f029fb43e1fd7e7b3d9ac9b diff --git a/include/AssetManager.h b/include/AssetManager.h index ee4a447..6dd5233 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -24,14 +24,12 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, TexturesEnum textureEnum, Entity* owner); - void createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath); + void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, Textures textureEnum, Entity* owner); + void createPowerup(Vector2D pos, std::function pickupFunc, Textures texture); Vector2D calculateSpawnPosition(); PowerupType calculateType(); - //texture management - void addTexture(std::string id, const char* path); // sound management void addSoundEffect(std::string id, const char* path); diff --git a/include/Map.h b/include/Map.h index 4c1bc3b..32184be 100644 --- a/include/Map.h +++ b/include/Map.h @@ -2,6 +2,7 @@ #include #include +#include class GameInternal; class Map @@ -21,6 +22,6 @@ public: * \return Boolean for success * */ - static void loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */); - static void addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict); + static void loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */); + static void addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict); }; diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index bbeac64..f887097 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -9,7 +9,6 @@ #include "AnimationHandler.h" #include "Component.h" #include "Direction.h" -#include "TextureEnumBase.h" class TransformComponent; @@ -25,7 +24,7 @@ private: SDL_Texture* texture; SDL_Rect srcRect, destRect; - TexturesEnum textureEnum; + Textures textureEnum; bool animated = false; uint8_t frames = 0; @@ -34,15 +33,15 @@ private: public: SpriteComponent() = default; - SpriteComponent(TexturesEnum textureEnum); + SpriteComponent(Textures textureEnum); SpriteComponent( - TexturesEnum textureEnum, + Textures textureEnum, bool isAnimated, std::map>* animationList, std::string defaultAnimation); ~SpriteComponent(); - void setTexture(TexturesEnum texture); + void setTexture(Textures texture); void init() override; void update() override; diff --git a/include/TextureEnumBase.h b/include/TextureEnumBase.h index 0857f12..75c3573 100644 --- a/include/TextureEnumBase.h +++ b/include/TextureEnumBase.h @@ -1,3 +1,3 @@ #pragma once -enum class TexturesEnum; \ No newline at end of file +enum class Textures; \ No newline at end of file diff --git a/include/TextureManager.h b/include/TextureManager.h index 2cc9469..cf6056c 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -18,12 +18,12 @@ class TextureManager } } - void addSingleTexture(TexturesEnum texture, const char* filePath); - void addTextures(const std::map& textures); - SDL_Texture* loadTexture(TexturesEnum texture); + void addSingleTexture(Textures texture, const char* filePath); + void addTextures(const std::map& textures); + SDL_Texture* loadTexture(Textures texture); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); private: Manager* manager; - std::map texture_cache; + std::map texture_cache; }; \ No newline at end of file diff --git a/include/TileComponent.h b/include/TileComponent.h index 8844daa..627bb93 100644 --- a/include/TileComponent.h +++ b/include/TileComponent.h @@ -3,8 +3,10 @@ #include #include #include +#include #include "Component.h" +#include "TextureEnumBase.h" class SpriteComponent; class TransformComponent; @@ -17,17 +19,27 @@ public: SDL_Rect tileRect; int tileID; - const char* path; + Textures texture; TileComponent() = default; - TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict); + TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict); ~TileComponent() = default; void init() override; - bool hasCollision(){return this->collision;} - std::string getName(){return this->tileName;} + bool hasCollision() { + return this->collision; + } + + std::string getName() { +#ifdef TEXTURE_ENUM_DEFINED + return std::string(magic_enum::enum_name(this->texture)); +#else + return "Undefined Enum"; +#endif + } + + private: bool collision; - std::string tileName; }; \ No newline at end of file diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index b2d960c..41c3889 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -21,11 +21,6 @@ AssetManager::AssetManager(Manager* manager) : man(manager) {} AssetManager::~AssetManager() {} -//seems to not be used anymore -void AssetManager::addTexture(std::string id, const char* path) { - //textures.emplace(id, this->man->getGame()->textureManager->loadTexture(path)); -} - void AssetManager::addSoundEffect(std::string id, const char* path) { soundEffects.emplace(id, this->man->getGame()->soundManager->loadSound(path)); @@ -49,7 +44,7 @@ Mix_Music* AssetManager::getMusic(std::string id) return music.at(id); } -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, TexturesEnum textureEnum, Entity* owner) { +void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, Textures textureEnum, Entity* owner) { auto& projectile(man->addEntity()); projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects @@ -59,13 +54,13 @@ void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE); } -void AssetManager::createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath) { +void AssetManager::createPowerup(Vector2D pos, std::function pickupFunc, Textures texture) { auto& powerups(man->addEntity()); powerups.addComponent(pos.x, pos.y, 32, 32, 1); //32x32 is standard size for objects try { - powerups.addComponent(texturePath.c_str()); + powerups.addComponent(texture); } catch (std::runtime_error e) { std::cout << e.what() << std::endl; diff --git a/src/Map.cpp b/src/Map.cpp index 5689d9e..796002d 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -10,7 +10,7 @@ #include "SDL_error.h" #include "TileComponent.h" -void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */) +void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */) { std::string tileIDstr; char singleChar = 0; @@ -56,11 +56,13 @@ void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, co mapFile.close(); } -void Map::addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict) // tile entity +void Map::addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict) // tile entity { auto& tile(game->manager.addEntity()); tile.addComponent(x, y, TILE_SIZE, TILE_SIZE, id, textureDict); - if(tile.getComponent().hasCollision()) tile.addComponent(tile.getComponent().getName().data()); + if(tile.getComponent().hasCollision()) + tile.addComponent(tile.getComponent().getName().data()); + tile.addGroup((size_t)Entity::GroupLabel::MAPTILES); } \ No newline at end of file diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 8ec85e9..d7728ab 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -12,13 +12,13 @@ #include "GameInternal.h" #include "Manager.h" -SpriteComponent::SpriteComponent(TexturesEnum textureEnum) +SpriteComponent::SpriteComponent(Textures textureEnum) { this->textureEnum = textureEnum; } SpriteComponent::SpriteComponent( - TexturesEnum textureEnum, + Textures textureEnum, bool isAnimated, std::map>* animationMap, std::string defaultAnimation) @@ -34,7 +34,7 @@ SpriteComponent::SpriteComponent( SpriteComponent::~SpriteComponent() {} -void SpriteComponent::setTexture(TexturesEnum texture) +void SpriteComponent::setTexture(Textures texture) { this->texture = this->entity->getManager().getGame()->textureManager->loadTexture(texture); } diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index 03852ad..ff2b697 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -7,7 +7,7 @@ #include "GameInternal.h" -void TextureManager::addSingleTexture(TexturesEnum texture, const char* filePath) { +void TextureManager::addSingleTexture(Textures texture, const char* filePath) { auto sdlTexture = IMG_LoadTexture(this->manager->getGame()->renderer, filePath); if (sdlTexture == nullptr) @@ -17,14 +17,14 @@ void TextureManager::addSingleTexture(TexturesEnum texture, const char* filePath std::cout << "Loaded texture at " << filePath << std::endl; } -void TextureManager::addTextures(const std::map &textures) { +void TextureManager::addTextures(const std::map &textures) { for (auto texture : textures) { addSingleTexture(texture.first, texture.second); } } -SDL_Texture* TextureManager::loadTexture(TexturesEnum texture) { +SDL_Texture* TextureManager::loadTexture(Textures texture) { auto it = this->texture_cache.find(texture); if (it != this->texture_cache.end()) diff --git a/src/TileComponent.cpp b/src/TileComponent.cpp index 8658e93..3664e19 100644 --- a/src/TileComponent.cpp +++ b/src/TileComponent.cpp @@ -9,7 +9,7 @@ #include "TextureEnumBase.h" -TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict) +TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict) { this->tileRect.x = x; this->tileRect.y = y; @@ -24,8 +24,7 @@ TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map< } this->collision = it->second.second; - this->tileName = it->second.first; - this->path = it->second.first.data(); + this->texture = it->second.first; } void TileComponent::init() @@ -33,7 +32,7 @@ void TileComponent::init() this->entity->addComponent(this->tileRect.x, this->tileRect.y, this->tileRect.w, this->tileRect.h, 1); this->transform = &entity->getComponent(); - this->entity->addComponent(this->path); + this->entity->addComponent(this->texture); this->sprite = &entity->getComponent(); } From ac217e931baf79f33bcc177563293775fa6f7ae0 Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 17 Nov 2024 16:59:46 +0100 Subject: [PATCH 08/42] added new Map for tile-textures as they wont work with our current enum-class maps. --- include/TextureManager.h | 4 ++++ src/Map.cpp | 3 ++- src/TextureManager.cpp | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/TextureManager.h b/include/TextureManager.h index cf6056c..9925705 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -23,7 +23,11 @@ class TextureManager SDL_Texture* loadTexture(Textures texture); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); + + SDL_Texture* loadMapTileTexture(const char* path); + private: Manager* manager; std::map texture_cache; + std::map mapTile_texture_cache; }; \ No newline at end of file diff --git a/src/Map.cpp b/src/Map.cpp index 6b72837..9eb9212 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -104,7 +104,7 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) tmx::Vector2i textureSize; SDL_QueryTexture( - VEGO_Game().textureManager->loadTexture(texturePath), + VEGO_Game().textureManager->loadMapTileTexture(texturePath), nullptr, nullptr, &(textureSize.x), @@ -170,6 +170,7 @@ void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int tile.addComponent(x, y, mapTileSize.x, mapTileSize.y, 1); tile.addComponent(texturePath.c_str(), v, u, zIndex); // why does uv need to be reversed? + //TODO: also implement updated map stuff for this if (hasCollision) { // tag currently does not have a clear purposes, TODO: figure out appropriate tag name diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index ff2b697..1a85fd1 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -3,12 +3,14 @@ #include #include #include +#include +#include #include "GameInternal.h" void TextureManager::addSingleTexture(Textures texture, const char* filePath) { - auto sdlTexture = IMG_LoadTexture(this->manager->getGame()->renderer, filePath); + auto sdlTexture = IMG_LoadTexture(VEGO_Game().renderer, filePath); if (sdlTexture == nullptr) throw std::runtime_error(std::string("Couldn't load texture '") + filePath + "'"); @@ -38,4 +40,17 @@ void TextureManager::draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect { SDL_RendererFlip flip = flipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; SDL_RenderCopyEx(renderer, texture, &src, &dest, 0, NULL, flip); -} \ No newline at end of file +} + +SDL_Texture* TextureManager::loadMapTileTexture(const char *path) { + + //returns tile if it exists already + if(mapTile_texture_cache.contains(std::string(path))) + return mapTile_texture_cache.at(std::string(path)); + + auto newTexture = IMG_LoadTexture(VEGO_Game().renderer, path); + + this->mapTile_texture_cache.emplace(std::string(path), newTexture); + + return newTexture; +} From 27a80d9766f71328244e69d46ba26c85e47eeddb Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 17 Nov 2024 17:05:26 +0100 Subject: [PATCH 09/42] added new Constructor for SpriteComponent as Tiles wont work with enums --- include/SpriteComponent.h | 4 ++++ src/SpriteComponent.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 5cc3b53..4b9f8e2 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -35,9 +35,13 @@ private: int textureXOffset; int textureYOffset; + //should be changed in the future as this is only for the tiles + const char* path; + public: SpriteComponent(Textures texture, int zIndex); SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex); + SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex); SpriteComponent( Textures texture, bool isAnimated, diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 36f6766..77ad9f1 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -25,6 +25,11 @@ SpriteComponent::SpriteComponent(Textures texture, int xOffset, int yOffset, int this->textureEnum = texture; } +SpriteComponent::SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) { + + this->path = path; +} + SpriteComponent::SpriteComponent( Textures texture, bool isAnimated, From 625ac98a57d7979ead3c2280e87e88aac96b59ce Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Mon, 18 Nov 2024 13:29:30 +0100 Subject: [PATCH 10/42] first pass - changed function names etc. --- .gitmodules | 4 ---- CMakeLists.txt | 9 ++++----- engine.sublime-project | 15 +++++++++------ extern/SDL | 2 +- extern/SDL_image | 2 +- extern/SDL_mixer | 2 +- extern/SDL_ttf | 2 +- include/AssetManager.h | 4 ++-- include/ColliderComponent.h | 2 +- include/CollisionHandler.h | 2 +- include/GameInternal.h | 6 +++--- include/InputComponent.h | 4 ++-- include/Map.h | 2 +- include/SoundManager.h | 2 +- include/SpriteComponent.h | 4 ++-- include/TextureManager.h | 8 ++++++-- include/TileComponent.h | 2 +- include/Vector2D.h | 4 ++-- src/AssetManager.cpp | 2 +- src/CollisionHandler.cpp | 8 ++++---- src/GameInternal.cpp | 19 +++++++------------ src/Map.cpp | 12 +++++------- src/SoundManager.cpp | 10 ++++++---- src/SpriteComponent.cpp | 2 +- src/TextureManager.cpp | 8 ++++---- src/Vector2D.cpp | 2 +- src/main.cpp | 1 + 27 files changed, 69 insertions(+), 71 deletions(-) diff --git a/.gitmodules b/.gitmodules index 84e7c1b..0781886 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,19 +1,15 @@ [submodule "SDL"] path = extern/SDL url = https://github.com/libsdl-org/SDL.git - branch = release-2.28.x [submodule "SDL_image"] path = extern/SDL_image url = https://github.com/libsdl-org/SDL_image.git - branch = release-2.8.x [submodule "extern/SDL_mixer"] path = extern/SDL_mixer url = https://github.com/libsdl-org/SDL_mixer.git - branch = release-2.8.x [submodule "extern/SDL_ttf"] path = extern/SDL_ttf url = https://github.com/libsdl-org/SDL_ttf.git - branch = release-2.22.x [submodule "extern/tmxlite"] path = extern/tmxlite url = https://github.com/fallahn/tmxlite.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 8934839..8bc9a02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,11 +31,10 @@ add_library(${PROJECT_NAME} ${SOURCES}) target_include_directories(${PROJECT_NAME} PUBLIC ${ENGINE_INCLUDE_DIR}) target_link_libraries(${PROJECT_NAME} PUBLIC # should be private when all SDL functionality has a wrapper - SDL2::SDL2main - SDL2::SDL2-static - SDL2_image::SDL2_image-static - SDL2_mixer::SDL2_mixer-static - SDL2_ttf::SDL2_ttf-static + SDL3::SDL3-static + SDL3_image::SDL3_image-static + SDL3_mixer::SDL3_mixer-static + SDL3_ttf::SDL3_ttf-static tmxlite ) diff --git a/engine.sublime-project b/engine.sublime-project index 1466f8e..a2490fa 100644 --- a/engine.sublime-project +++ b/engine.sublime-project @@ -2,12 +2,12 @@ "folders": [ { - "path": "." + "path": ".", } - ], + ], "settings": { - "tab_size": 4 + "tab_size": 4, }, "build_systems": [ { @@ -23,7 +23,7 @@ "name": "Release", "shell_cmd": "cmake -DCMAKE_BUILD_TYPE=Release build && cmake --build build", }, - ] + ], }, { "name": "Generate CMake", @@ -43,7 +43,10 @@ "name": "Generate documentation", "shell_cmd": "docker run --rm -v \"$project_path:/source\" -v \"$project_path/docs:/output\" -v \"$project_path/docs/Doxyfile:/Doxyfile\" vego_engine-docker", }, - ] + ], } - ] + ], + "debugger_configurations": + [ + ], } diff --git a/extern/SDL b/extern/SDL index 05eb080..e027b85 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit 05eb08053d48fea9052ad02b3d619244aeb868d3 +Subproject commit e027b85cc457556071cbb2f3f1bcf8803c1bc001 diff --git a/extern/SDL_image b/extern/SDL_image index abcf63a..b1c8ec7 160000 --- a/extern/SDL_image +++ b/extern/SDL_image @@ -1 +1 @@ -Subproject commit abcf63aa71b4e3ac32120fa9870a6500ddcdcc89 +Subproject commit b1c8ec7d75e3d8398940c9e04a8b82886ae6163d diff --git a/extern/SDL_mixer b/extern/SDL_mixer index 5bcd40a..5e2a705 160000 --- a/extern/SDL_mixer +++ b/extern/SDL_mixer @@ -1 +1 @@ -Subproject commit 5bcd40ad962dc72a3c051084ce128d78f7656566 +Subproject commit 5e2a70519294bc6ec44f1870b019ecd4760fde7d diff --git a/extern/SDL_ttf b/extern/SDL_ttf index 4a318f8..4a8bda9 160000 --- a/extern/SDL_ttf +++ b/extern/SDL_ttf @@ -1 +1 @@ -Subproject commit 4a318f8dfaa1bb6f10e0c5e54052e25d3c7f3440 +Subproject commit 4a8bda9197cc4d6fafd188bc9df6c7e8749a43a2 diff --git a/include/AssetManager.h b/include/AssetManager.h index 1d3c97a..212828c 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include #include #include #include diff --git a/include/ColliderComponent.h b/include/ColliderComponent.h index ef4d5c8..b49fd33 100644 --- a/include/ColliderComponent.h +++ b/include/ColliderComponent.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "Component.h" #include "Vector2D.h" diff --git a/include/CollisionHandler.h b/include/CollisionHandler.h index 9802f7d..43aa0ae 100644 --- a/include/CollisionHandler.h +++ b/include/CollisionHandler.h @@ -7,7 +7,7 @@ #include "ColliderComponent.h" #include "Constants.h" #include "Entity.h" -#include "SDL_rect.h" +#include #include "SpriteComponent.h" #include "Vector2D.h" #include "Manager.h" diff --git a/include/GameInternal.h b/include/GameInternal.h index 44cec2d..57b9aac 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/InputComponent.h b/include/InputComponent.h index 9382cf1..8d62202 100644 --- a/include/InputComponent.h +++ b/include/InputComponent.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include "Component.h" @@ -99,7 +99,7 @@ public: bool isKeyDown(Key key); private: - const Uint8* m_keyStates; + const bool* m_keyStates; SDL_Scancode mapKeyToSDL(Key key); std::map m_keyMappings; void InitKeyMappings(); diff --git a/include/Map.h b/include/Map.h index 244322e..58ebf4d 100644 --- a/include/Map.h +++ b/include/Map.h @@ -34,7 +34,7 @@ private: struct TileSetData { std::string texturePath{}; - tmx::Vector2i textureSize; + tmx::Vector2f textureSize; uint32_t tileCount{}; tmx::Vector2u tileCount2D; uint32_t firstGID{}; diff --git a/include/SoundManager.h b/include/SoundManager.h index 8663d34..38a6b2c 100644 --- a/include/SoundManager.h +++ b/include/SoundManager.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 0676549..f8077cd 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -22,7 +22,7 @@ public: private: TransformComponent* transform; SDL_Texture* texture; - SDL_Rect srcRect, destRect; + SDL_FRect srcRect, destRect; const char* texturePath; diff --git a/include/TextureManager.h b/include/TextureManager.h index 3e4f1c4..22f19ed 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -1,7 +1,8 @@ #pragma once #include "ECS.h" -#include +#include "SDL3/SDL_surface.h" +#include #include #include #include @@ -21,7 +22,10 @@ class TextureManager SDL_Texture* loadTexture(const char* fileName); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); - static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); + static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect src, SDL_FRect dest, bool flipped = false); + + void setScaleMode(SDL_ScaleMode scaleMode) { this->scaleMode = scaleMode; } private: + SDL_ScaleMode scaleMode = SDL_SCALEMODE_NEAREST; Manager* manager; }; \ No newline at end of file diff --git a/include/TileComponent.h b/include/TileComponent.h index 8844daa..ecdbfc6 100644 --- a/include/TileComponent.h +++ b/include/TileComponent.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/include/Vector2D.h b/include/Vector2D.h index bc2d652..9b38e18 100644 --- a/include/Vector2D.h +++ b/include/Vector2D.h @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include +#include class Vector2D { diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 25ce8ad..e4b1cf4 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -86,7 +86,7 @@ Vector2D AssetManager::calculateSpawnPosition() conflict = false; for (auto cc : this->man->getGame()->collisionHandler->getColliders({ Entity::GroupLabel::MAPTILES })) { - if (SDL_HasIntersection(&spawnRect, &cc->collider) && strcmp(cc->tag, "projectile")) + if (SDL_HasRectIntersection(&spawnRect, &cc->collider) && strcmp(cc->tag, "projectile")) { conflict = true; break; diff --git a/src/CollisionHandler.cpp b/src/CollisionHandler.cpp index 5477c6c..5821303 100644 --- a/src/CollisionHandler.cpp +++ b/src/CollisionHandler.cpp @@ -6,7 +6,7 @@ #include "Manager.h" #include "Vector2D.h" -#include +#include #include #include #include @@ -26,7 +26,7 @@ IntersectionBitSet CollisionHandler::getIntersection(Entity* entityA, Entity* en colliderB.x += posModB.x; colliderB.y += posModB.y; - if (!SDL_HasIntersection( + if (!SDL_HasRectIntersection( &colliderA, &colliderB)) return std::bitset(); @@ -152,7 +152,7 @@ Entity* CollisionHandler::getAnyIntersection( if (!entity->hasComponent()) return nullptr; for (auto& collider : getColliders(groupLabels, excludedEntities)) { SDL_Rect rect = entity->getComponent().collider + posMod; - if (SDL_HasIntersection(&rect, &collider->collider)) { + if (SDL_HasRectIntersection(&rect, &collider->collider)) { return collider->entity; } } @@ -175,7 +175,7 @@ bool CollisionHandler::getAnyIntersection( if (!entity->hasComponent()) return false; for (auto& collider : getColliders(groupLabels, excludedEntities)) { SDL_Rect rect = entity->getComponent().collider + posMod; - if (SDL_HasIntersection(&rect, &collider->collider)) { + if (SDL_HasRectIntersection(&rect, &collider->collider)) { return true; } } diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 0ef8c69..d3a65dc 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -1,20 +1,15 @@ #include "GameInternal.h" -#include - #include "CollisionHandler.h" #include "AssetManager.h" #include "RenderManager.h" -#include "SDL_mixer.h" +#include +#include "SDL3/SDL_init.h" #include "SoundManager.h" -#include "TileComponent.h" -#include "Direction.h" #include "Entity.h" #include "HealthComponent.h" #include "Map.h" #include "TextureManager.h" -#include "StatEffectsComponent.h" -#include "Constants.h" #include "Game.h" #include "GameFactory.h" @@ -43,7 +38,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he flags = SDL_WINDOW_FULLSCREEN; } - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) + if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) { std::cout << "ERROR. Subsystem couldnt be initialized! " << SDL_GetError() << std::endl; SDL_ClearError(); @@ -55,7 +50,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he return; } - window = SDL_CreateWindow(title, xpos, ypos, width, height, flags); + window = SDL_CreateWindow(title, width, height, flags); if (!window) { std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; @@ -72,7 +67,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he SDL_SetWindowIcon(window, icon); - renderer = SDL_CreateRenderer(window, -1, 0); + renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { std::cout << "ERROR: Renderer couldnt be created! " << SDL_GetError() << std::endl; @@ -81,7 +76,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he } SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) + if (!Mix_OpenAudio(0, NULL)) { std::cout << "ERROR: Mixer couldnt be initialized! " << SDL_GetError() << std::endl; SDL_ClearError(); @@ -108,7 +103,7 @@ void GameInternal::handleEvents() switch (event.type) { - case SDL_QUIT: this->setRunning(false); + case SDL_EVENT_QUIT: this->setRunning(false); break; default: diff --git a/src/Map.cpp b/src/Map.cpp index dab109b..467a7a2 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -9,8 +9,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -102,16 +102,14 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) | std::views::transform([&](uint16_t i) { const char* texturePath = this->mapData.texturePaths->at(i).c_str(); - tmx::Vector2i textureSize; - SDL_QueryTexture( + tmx::Vector2f textureSize; + SDL_GetTextureSize( VEGO_Game().textureManager->loadTexture(texturePath), - nullptr, - nullptr, &(textureSize.x), &(textureSize.y) ); - tmx::Vector2u tileCount2D = { textureSize.x / this->mapData.mapTileSize->x, textureSize.y / this->mapData.mapTileSize->y }; + tmx::Vector2u tileCount2D = { static_cast(textureSize.x / this->mapData.mapTileSize->x), static_cast(textureSize.y / this->mapData.mapTileSize->y) }; uint32_t tileCount = this->mapData.tileSets->at(i).getTileCount(); uint32_t firstGID = this->mapData.tileSets->at(i).getFirstGID(); diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 2954b9f..3f101e2 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "GameInternal.h" #include "AssetManager.h" @@ -65,12 +67,12 @@ void SoundManager::playSound(GameInternal* game, std::string sound, bool canOver if(Mix_VolumeChunk(game->assets->getSound(sound), volume) == -1) { - std::cerr << "Error adjusting volume: " << Mix_GetError() << std::endl; + std::cerr << "Error adjusting volume: " /*<< Mix_GetError()*/ << std::endl; } if (Mix_PlayChannel(channel, game->assets->getSound(sound), loops) == -1) { - std::cerr << "Error playing sound '" << sound << "': " << Mix_GetError() << std::endl; + std::cerr << "Error playing sound '" << sound << "': " /*<< Mix_GetError()*/ << std::endl; } } @@ -87,12 +89,12 @@ void SoundManager::playMusic(GameInternal* game, std::string music, int loops, i if(Mix_VolumeMusic(volume) == -1) { - std::cerr << "Error adjusting volume: " << Mix_GetError() << std::endl; + std::cerr << "Error adjusting volume: " /*<< Mix_GetError()*/ << std::endl; } if (Mix_PlayMusic(game->assets->getMusic(music), loops) == -1) { - std::cerr << "Error playing music '" << music << "': " << Mix_GetError() << std::endl; + std::cerr << "Error playing music '" << music << "': " /*<< Mix_GetError()*/ << std::endl; } } diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index ae27ea7..026f8dc 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -1,6 +1,6 @@ #include "SpriteComponent.h" -#include +#include #include #include diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index 3e46d46..b31ee25 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -1,6 +1,5 @@ #include "TextureManager.h" -#include #include #include @@ -14,13 +13,14 @@ SDL_Texture* TextureManager::loadTexture(const char* fileName) } auto texture = IMG_LoadTexture(this->manager->getGame()->renderer, fileName); if (texture == NULL) throw std::runtime_error(std::string("Couldn't load texture '") + fileName + "'"); + SDL_SetTextureScaleMode(texture, this->scaleMode); // linear scaling results in blurry images this->texture_cache.emplace(std::string(fileName), texture); printf("Loaded texture at '%s'\n", fileName); return texture; } -void TextureManager::draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped) +void TextureManager::draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect src, SDL_FRect dest, bool flipped) { - SDL_RendererFlip flip = flipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; - SDL_RenderCopyEx(renderer, texture, &src, &dest, 0, NULL, flip); + SDL_FlipMode flip = flipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + SDL_RenderTextureRotated(renderer, texture, &src, &dest, 0, NULL, flip); } \ No newline at end of file diff --git a/src/Vector2D.cpp b/src/Vector2D.cpp index 6368ff3..530e316 100644 --- a/src/Vector2D.cpp +++ b/src/Vector2D.cpp @@ -1,5 +1,5 @@ #include "Vector2D.h" -#include "SDL_rect.h" +#include Vector2D::Vector2D() { diff --git a/src/main.cpp b/src/main.cpp index da7f8a6..33bccd7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "VEGO.h" #include "Entity.h" From 25414524a0fd9fad65a469db19c6a90ed09c1968 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Mon, 18 Nov 2024 16:20:41 +0100 Subject: [PATCH 11/42] new main logic & new time keeping --- include/AssetManager.h | 2 +- include/ColliderComponent.h | 2 +- include/Component.h | 3 ++- include/Entity.h | 2 +- include/Game.h | 2 +- include/GameInternal.h | 7 +++-- include/InputComponent.h | 2 +- include/Manager.h | 2 +- include/PowerupComponent.h | 2 +- include/ProjectileComponent.h | 6 ++--- include/SpriteComponent.h | 2 +- include/StatEffectsComponent.h | 2 +- include/TransformComponent.h | 4 +-- src/AssetManager.cpp | 2 +- src/ColliderComponent.cpp | 4 +-- src/Entity.cpp | 4 +-- src/GameInternal.cpp | 26 +++++++++++------- src/InputComponent.cpp | 2 +- src/Manager.cpp | 4 +-- src/PowerupComponent.cpp | 2 +- src/ProjectileComponent.cpp | 6 ++--- src/SoundManager.cpp | 1 - src/SpriteComponent.cpp | 6 ++--- src/StatEffectsComponent.cpp | 10 +++---- src/TransformComponent.cpp | 6 ++--- src/_Init.cpp | 48 ++++++++++++++++++++++++++++++++++ src/main.cpp | 42 ----------------------------- 27 files changed, 109 insertions(+), 92 deletions(-) create mode 100644 src/_Init.cpp delete mode 100644 src/main.cpp diff --git a/include/AssetManager.h b/include/AssetManager.h index 212828c..541fa04 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -24,7 +24,7 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner); + void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, const char* texturePath, Entity* owner); void createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath); Vector2D calculateSpawnPosition(); diff --git a/include/ColliderComponent.h b/include/ColliderComponent.h index b49fd33..91280c0 100644 --- a/include/ColliderComponent.h +++ b/include/ColliderComponent.h @@ -22,7 +22,7 @@ public: ColliderComponent(const char* tag, float hitboxScale); void init() override; - void update() override; + void update(uint_fast16_t diffTime) override; void removeCollision(); void handleCollision(Vector2D& characterPos, SDL_Rect& characterCollider, SDL_Rect& componentCollider); diff --git a/include/Component.h b/include/Component.h index 566fee9..5003dc3 100644 --- a/include/Component.h +++ b/include/Component.h @@ -1,5 +1,6 @@ #pragma once +#include class Entity; class Component @@ -8,7 +9,7 @@ public: Entity* entity; virtual void init() {} - virtual void update() {} + virtual void update(uint_fast16_t diffTime) {} virtual ~Component() = default; }; \ No newline at end of file diff --git a/include/Entity.h b/include/Entity.h index aa067a4..0ce952c 100644 --- a/include/Entity.h +++ b/include/Entity.h @@ -59,7 +59,7 @@ public: explicit Entity(Manager& mManager) : manager(mManager) { }; - void update() const; //!< Call each frame to update all components + void update(uint_fast16_t diffTime) const; //!< Call each frame to update all components bool isActive() const { return this->active; } //!< \sa destroy() //! Mark for destruction for Manager::refresh() and disables collision diff --git a/include/Game.h b/include/Game.h index c1b1aa3..3eb990d 100644 --- a/include/Game.h +++ b/include/Game.h @@ -8,7 +8,7 @@ public: virtual ~Game() {} virtual void init() = 0; - virtual void update() = 0; + virtual void update(uint_fast16_t diffTime) = 0; GameInternal* gameInternal; //!< \deprecated }; diff --git a/include/GameInternal.h b/include/GameInternal.h index 57b9aac..7cb3b1f 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -26,10 +27,10 @@ public: GameInternal(); ~GameInternal(); - void init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen); + SDL_AppResult init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen); void handleEvents(); - void update(); + void update(Uint64 frameTime); void render(); void clean(); bool isRunning() const; @@ -63,4 +64,6 @@ private: int counter = 0; bool running = true; SDL_Window* window; + + Uint64 lastFrameTime = 0; }; diff --git a/include/InputComponent.h b/include/InputComponent.h index 8d62202..31cd381 100644 --- a/include/InputComponent.h +++ b/include/InputComponent.h @@ -94,7 +94,7 @@ public: ~InputComponent(); void init() override; - void update() override; + void update(uint_fast16_t diffTime) override; bool isKeyDown(Key key); diff --git a/include/Manager.h b/include/Manager.h index 8b9ceb3..a796e42 100644 --- a/include/Manager.h +++ b/include/Manager.h @@ -24,7 +24,7 @@ class Manager public: Manager(GameInternal* game) : game(game) {}; - void update(); //!< \sa Entity::update() + void update(uint_fast16_t diffTime); //!< \sa Entity::update() //! Disables all functionality of entities marked for destruction //! \sa Entity::destroy() void refresh(); diff --git a/include/PowerupComponent.h b/include/PowerupComponent.h index 53f365b..a0a3f36 100644 --- a/include/PowerupComponent.h +++ b/include/PowerupComponent.h @@ -9,7 +9,7 @@ public: PowerupComponent(std::function func); ~PowerupComponent() {}; - void update() override; + void update(uint_fast16_t diffTime) override; private: std::function pickupFunc; diff --git a/include/ProjectileComponent.h b/include/ProjectileComponent.h index 4db0bfd..da67ff6 100644 --- a/include/ProjectileComponent.h +++ b/include/ProjectileComponent.h @@ -16,14 +16,14 @@ public: ~ProjectileComponent() {} void init() override; - void update() override; + void update(uint_fast16_t diffTime) override; private: TransformComponent* transformComponent; int range = 0; - int speed = 0; - int distance = 0; + float speed = 0; + float distance = 0; Entity* owner = nullptr; diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index f8077cd..6966977 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -48,7 +48,7 @@ public: void setTexture(const char* path); void init() override; - void update() override; + void update(uint_fast16_t diffTime) override; void draw() override; void playAnimation(std::string type); void setDirection(Direction direction); diff --git a/include/StatEffectsComponent.h b/include/StatEffectsComponent.h index bc93f2b..ca32d05 100644 --- a/include/StatEffectsComponent.h +++ b/include/StatEffectsComponent.h @@ -16,7 +16,7 @@ public: ~StatEffectsComponent() {}; void init() override; - void update() override; + void update(uint_fast16_t diffTime) override; void modifyStatDur(Stats stat, int duration, int value); diff --git a/include/TransformComponent.h b/include/TransformComponent.h index 7a15aa4..c325fce 100644 --- a/include/TransformComponent.h +++ b/include/TransformComponent.h @@ -25,11 +25,11 @@ public: void init() override; /*! TODO: document usage of collision handler */ - void update() override; + void update(uint_fast16_t diffTime) override; void setPositionAfterCollision(Vector2D& positionChange); void modifySpeed(int8_t modifier); private: - int speed = 3; + int speed = 180; int speedMod = 0; }; diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index e4b1cf4..ef32ce8 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -46,7 +46,7 @@ Mix_Music* AssetManager::getMusic(std::string id) return music.at(id); } -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner) { +void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, const char* texturePath, Entity* owner) { auto& projectile(man->addEntity()); projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects diff --git a/src/ColliderComponent.cpp b/src/ColliderComponent.cpp index 2275163..8cb2ad6 100644 --- a/src/ColliderComponent.cpp +++ b/src/ColliderComponent.cpp @@ -31,10 +31,10 @@ void ColliderComponent::init() } transform = &entity->getComponent(); - this->update(); + this->update(0); } -void ColliderComponent::update() +void ColliderComponent::update(uint_fast16_t diffTime) { collider.x = transform->position.x - (transform->width - transform->width * transform->scale * this->hitboxScale) / 2; collider.y = transform->position.y - (transform->width - transform->width * transform->scale * this->hitboxScale) / 2; diff --git a/src/Entity.cpp b/src/Entity.cpp index 60455c1..987626d 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -4,9 +4,9 @@ #include "Component.h" #include -void Entity::update() const +void Entity::update(uint_fast16_t diffTime) const { - for (auto const& c : components) c->update(); + for (auto const& c : components) c->update(diffTime); } bool Entity::hasGroup(Group mGroup) diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index d3a65dc..1e4eac3 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -13,6 +13,8 @@ #include "Game.h" #include "GameFactory.h" +#include + GameInternal::GameInternal() : manager(this), renderManager(), @@ -25,7 +27,7 @@ GameInternal::GameInternal() : GameInternal::~GameInternal() = default; -void GameInternal::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen) +SDL_AppResult GameInternal::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen) { GameInternal::assets = new AssetManager(&manager); GameInternal::textureManager = new TextureManager(&manager); @@ -42,12 +44,12 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he { std::cout << "ERROR. Subsystem couldnt be initialized! " << SDL_GetError() << std::endl; SDL_ClearError(); - return; + return SDL_APP_FAILURE; } if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { std::cout << "ERROR. Subsystem couldnt be initialized!" << std::endl; - return; + return SDL_APP_FAILURE; } window = SDL_CreateWindow(title, width, height, flags); @@ -55,7 +57,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he { std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; SDL_ClearError(); - return; + return SDL_APP_FAILURE; } // bad @@ -72,7 +74,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he { std::cout << "ERROR: Renderer couldnt be created! " << SDL_GetError() << std::endl; SDL_ClearError(); - return; + return SDL_APP_FAILURE; } SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); @@ -80,7 +82,7 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he { std::cout << "ERROR: Mixer couldnt be initialized! " << SDL_GetError() << std::endl; SDL_ClearError(); - return; + return SDL_APP_FAILURE; } Mix_Volume(-1, MIX_MAX_VOLUME); @@ -95,6 +97,8 @@ void GameInternal::init(const char* title, int xpos, int ypos, int width, int he this->gameInstance = GameFactory::instance().create(this); this->gameInstance->init(); + + return SDL_APP_CONTINUE; } void GameInternal::handleEvents() @@ -111,12 +115,16 @@ void GameInternal::handleEvents() } } -void GameInternal::update() +void GameInternal::update(Uint64 frameTime) { manager.refresh(); - manager.update(); - this->gameInstance->update(); // TODO: this might have to be split up into two update functions, before and after manager... + uint_fast16_t diffTime = frameTime - this->lastFrameTime; + manager.update(diffTime); + + this->gameInstance->update(diffTime); // TODO: this might have to be split up into two update functions, before and after manager... + + this->lastFrameTime = frameTime; } void GameInternal::render() diff --git a/src/InputComponent.cpp b/src/InputComponent.cpp index ac26b32..8f31ad4 100644 --- a/src/InputComponent.cpp +++ b/src/InputComponent.cpp @@ -10,7 +10,7 @@ InputComponent::~InputComponent() = default; void InputComponent::init(){} -void InputComponent::update() +void InputComponent::update(uint_fast16_t diffTime) { SDL_PumpEvents(); } diff --git a/src/Manager.cpp b/src/Manager.cpp index 09eea97..31e42a4 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -27,9 +27,9 @@ void Manager::refresh() std::end(entities)); } -void Manager::update() +void Manager::update(uint_fast16_t diffTime) { - for (auto& e : entities) e->update(); + for (auto& e : entities) e->update(diffTime); } void Manager::addToGroup(Entity* mEntity, Group mGroup) diff --git a/src/PowerupComponent.cpp b/src/PowerupComponent.cpp index 5c1df71..4db3f95 100644 --- a/src/PowerupComponent.cpp +++ b/src/PowerupComponent.cpp @@ -12,7 +12,7 @@ PowerupComponent::PowerupComponent(std::function func) this->pickupFunc = func; } -void PowerupComponent::update() +void PowerupComponent::update(uint_fast16_t diffTime) { Entity* player; if ((player = this->entity->getManager().getGame()->collisionHandler->getAnyIntersection( diff --git a/src/ProjectileComponent.cpp b/src/ProjectileComponent.cpp index 11599c8..2596009 100644 --- a/src/ProjectileComponent.cpp +++ b/src/ProjectileComponent.cpp @@ -17,9 +17,9 @@ void ProjectileComponent::init() SoundManager::playSound(this->entity->getManager().getGame(), "throw_egg", true, PLAY_ONCE, MAX_VOLUME, -1); } -void ProjectileComponent::update() +void ProjectileComponent::update(uint_fast16_t diffTime) { - distance += speed; + distance += speed * diffTime * (1.f/1000); IntersectionBitSet boundsIntersection = this->entity->getManager().getGame()->collisionHandler->getIntersectionWithBounds(entity); @@ -27,7 +27,7 @@ void ProjectileComponent::update() this->entity->destroy(); } - if (distance > range) { + if (distance > range && false) { this->entity->destroy(); } diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 3f101e2..182d616 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -1,6 +1,5 @@ #include "SoundManager.h" -#include #include #include diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 026f8dc..e646289 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -59,14 +59,14 @@ void SpriteComponent::init() this->srcRect.x = this->textureXOffset * this->srcRect.w; this->srcRect.y = this->textureYOffset * this->srcRect.h;; - this->update(); + this->update(0); } -void SpriteComponent::update() +void SpriteComponent::update(uint_fast16_t diffTime) { // This code is not compatible for animated tiles if (animated) { - srcRect.x = srcRect.w * static_cast((SDL_GetTicks() / speed) % frames); + srcRect.x = srcRect.w * static_cast((SDL_GetTicks() / speed) % frames); // TODO: should not call SDL_GetTicks() but use diffTime srcRect.y = animationIndex * transform->height; } diff --git a/src/StatEffectsComponent.cpp b/src/StatEffectsComponent.cpp index c66e206..05ab31a 100644 --- a/src/StatEffectsComponent.cpp +++ b/src/StatEffectsComponent.cpp @@ -8,16 +8,16 @@ void StatEffectsComponent::init() {} -void StatEffectsComponent::update() +void StatEffectsComponent::update(uint_fast16_t diffTime) { for (int i = 0; i < MAX_STATS; i++) { - if (this->buffs.at(i) == 0) continue; - if (this->buffs.at(i) - 1 == 0) + if (this->buffs.at(i) <= 0) continue; + if (this->buffs.at(i) - diffTime <= 0) { this->resetStatValue((Stats)i); } - this->buffs.at(i) -= 1; + this->buffs.at(i) -= diffTime; } } @@ -32,7 +32,7 @@ void StatEffectsComponent::modifyStatValue(Stats stat, int modifier) //modifier switch (stat) { case Stats::MOVEMENT_SPEED: - this->entity->getComponent().modifySpeed(modifier); + this->entity->getComponent().modifySpeed(modifier * 60); break; case Stats::ATTACK_SPEED: // this->entity->getComponent().modifyAtkSpeed(modifier); diff --git a/src/TransformComponent.cpp b/src/TransformComponent.cpp index e8e299b..c50fb5a 100644 --- a/src/TransformComponent.cpp +++ b/src/TransformComponent.cpp @@ -50,12 +50,12 @@ void TransformComponent::init() direction.zero(); } -void TransformComponent::update() +void TransformComponent::update(uint_fast16_t diffTime) { float multiplier = direction.x != 0 && direction.y != 0 ? 0.707 : 1; // normalizes vector; only works if directions are in increments of 45° Vector2D positionChange( - direction.x * this->getSpeed() * multiplier, - direction.y * this->getSpeed() * multiplier + direction.x * this->getSpeed() * multiplier * diffTime * (1.f/1000), + direction.y * this->getSpeed() * multiplier * diffTime * (1.f/1000) ); if (this->entity->hasGroup((size_t)Entity::GroupLabel::PLAYERS)){ diff --git a/src/_Init.cpp b/src/_Init.cpp new file mode 100644 index 0000000..cb82136 --- /dev/null +++ b/src/_Init.cpp @@ -0,0 +1,48 @@ +#include "SDL3/SDL_init.h" +#include +#define SDL_MAIN_USE_CALLBACKS +#include + +#include +#include + +#include "VEGO.h" +#include "Entity.h" +#include "GameInternal.h" +#include "Constants.h" + +GameInternal* vego::game = nullptr; + +SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) { + srand(time(NULL)); + bool playing = true; + + *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); +} + +SDL_AppResult SDL_AppIterate(void *appstate) { + if (!vego::game->isRunning()) { + return SDL_APP_SUCCESS; + } + + vego::game->handleEvents(); // bad + + Uint64 frameStart = SDL_GetTicks(); + + vego::game->update(frameStart); + vego::game->render(); + + int frameTime = SDL_GetTicks() - frameStart; + + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void *appstate, SDL_AppResult result) { + vego::game->clean(); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 33bccd7..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include - -#include "VEGO.h" -#include "Entity.h" -#include "GameInternal.h" -#include "Constants.h" - -GameInternal* vego::game = nullptr; - -int main(int argc, char* argv[]) -{ - srand(time(NULL)); - bool playing = true; - - const int frameDelay = 1000 / FPS; - - Uint32 frameStart; - int frameTime; - - vego::game = new GameInternal(); - - vego::game->init("No_Name_Chicken_Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_SIZE_WIDTH, SCREEN_SIZE_HEIGHT, false); - while (vego::game->isRunning()) { - frameStart = SDL_GetTicks(); - - vego::game->handleEvents(); - vego::game->update(); - vego::game->render(); - - frameTime = SDL_GetTicks() - frameStart; - - if (frameDelay > frameTime) { - SDL_Delay(frameDelay - frameTime); - } - } - - vego::game->clean(); - - return 0; -} \ No newline at end of file From b497991975905acc2ada3f809e59e48b94cf25cb Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Tue, 19 Nov 2024 18:47:37 +0100 Subject: [PATCH 12/42] fixed developer skill issue --- src/ProjectileComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ProjectileComponent.cpp b/src/ProjectileComponent.cpp index 2596009..e1df015 100644 --- a/src/ProjectileComponent.cpp +++ b/src/ProjectileComponent.cpp @@ -27,7 +27,7 @@ void ProjectileComponent::update(uint_fast16_t diffTime) this->entity->destroy(); } - if (distance > range && false) { + if (distance > range) { this->entity->destroy(); } From cbd1993c20e8be78f447151067ebd7b1eb610f6d Mon Sep 17 00:00:00 2001 From: freezarite Date: Sat, 30 Nov 2024 14:55:40 +0100 Subject: [PATCH 13/42] Extra map for MapTiles generated by TMX file now works like intended. removed textures map from AssetManager as it is no longer used. Updated SpriteComponent to now check if it is a normal Texture or a MapTileTexture. Added if condition in TextureManager::LoadMapTileTexture to check if the texture was able to be loaded by SDL --- include/AssetManager.h | 2 -- include/SpriteComponent.h | 1 + include/TextureManager.h | 3 +++ src/AssetManager.cpp | 3 --- src/SpriteComponent.cpp | 18 ++++++++++++++++-- src/TextureManager.cpp | 5 ++++- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/AssetManager.h b/include/AssetManager.h index 6dd5233..154b7ea 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -36,14 +36,12 @@ public: void addMusic(std::string id, const char* path); - SDL_Texture* getTexture(std::string id); Mix_Chunk* getSound(std::string id); Mix_Music* getMusic(std::string id); private: Manager* man; - std::map textures; std::map soundEffects; std::map music; }; diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 4b9f8e2..444663d 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -51,6 +51,7 @@ public: ~SpriteComponent(); void setTexture(Textures texture); + void setMapTileTexture(const char* path); void init() override; void update() override; diff --git a/include/TextureManager.h b/include/TextureManager.h index 9925705..5e5cd02 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -16,6 +16,9 @@ class TextureManager for (auto& it : this->texture_cache) { SDL_DestroyTexture(it.second); } + for (auto& it : this->mapTile_texture_cache) { + SDL_DestroyTexture(it.second); + } } void addSingleTexture(Textures texture, const char* filePath); diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index f90b6d1..9ac14c1 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -31,9 +31,6 @@ void AssetManager::addMusic(std::string id, const char* path) music.emplace(id, this->man->getGame()->soundManager->loadMusic(path)); } -SDL_Texture* AssetManager::getTexture(std::string id) { - return textures.at(id); -} Mix_Chunk* AssetManager::getSound(std::string id) { return soundEffects.at(id); diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 77ad9f1..99c7690 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "AnimationHandler.h" #include "Direction.h" @@ -18,11 +19,13 @@ SpriteComponent::SpriteComponent(Textures texture, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0) { this->textureEnum = texture; + this->path = ""; } SpriteComponent::SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) { this->textureEnum = texture; + this->path = ""; } SpriteComponent::SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) { @@ -44,6 +47,8 @@ SpriteComponent::SpriteComponent( playAnimation(defaultAnimation); this->textureEnum = texture; + + this->path = ""; } SpriteComponent::~SpriteComponent() {} @@ -55,7 +60,12 @@ void SpriteComponent::setTexture(Textures texture) void SpriteComponent::init() { - setTexture(this->textureEnum); + if (this->path == "") { + setTexture(this->textureEnum); + } + else { + setMapTileTexture(this->path); + } this->transform = &entity->getComponent(); @@ -97,4 +107,8 @@ void SpriteComponent::playAnimation(std::string type) void SpriteComponent::setDirection(Direction direction) { this->flipped = direction == Direction::RIGHT; -} \ No newline at end of file +} + +void SpriteComponent::setMapTileTexture(const char *path) { + this->texture = VEGO_Game().textureManager->loadMapTileTexture(path); +} diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index 1a85fd1..ff8e2fd 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -46,10 +46,13 @@ SDL_Texture* TextureManager::loadMapTileTexture(const char *path) { //returns tile if it exists already if(mapTile_texture_cache.contains(std::string(path))) - return mapTile_texture_cache.at(std::string(path)); + return mapTile_texture_cache.find(std::string(path))->second; auto newTexture = IMG_LoadTexture(VEGO_Game().renderer, path); + if (newTexture == nullptr) + throw std::runtime_error(std::string("Couldn't load texture '") + path + "'"); + this->mapTile_texture_cache.emplace(std::string(path), newTexture); return newTexture; From 7dbcfe876cdd9a084d55be0c687e0642a55a8839 Mon Sep 17 00:00:00 2001 From: freezarite Date: Sat, 30 Nov 2024 15:35:03 +0100 Subject: [PATCH 14/42] Added some doxygen documentation to TextureEnumBase.h and TextureManager.h --- include/TextureEnumBase.h | 15 +++++++++++ include/TextureManager.h | 54 +++++++++++++++++++++++++++++++++++++++ src/TextureManager.cpp | 1 - 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/include/TextureEnumBase.h b/include/TextureEnumBase.h index 75c3573..e9e5d9a 100644 --- a/include/TextureEnumBase.h +++ b/include/TextureEnumBase.h @@ -1,3 +1,18 @@ +/*! + * \file Textures.h + * \brief Forward declaration of the \c Textures enum class. + * + * This file contains a forward declaration of the \c Textures enum class, which is used as a base + * class for texture identifiers in the engine. It allows developers to define their own set of texture + * types in their own implementation, providing flexibility in texture management within the engine. + * + * \details + * The \c Textures enum class is intended to be implemented by the developer within their own scope. + * This allows for customized texture entries to be defined based on the specific needs of the project. + * The base declaration ensures that the enum class can be referenced and used consistently throughout + * the engine while leaving the details of the texture identifiers up to the implementation. + */ + #pragma once enum class Textures; \ No newline at end of file diff --git a/include/TextureManager.h b/include/TextureManager.h index 5e5cd02..8789a2c 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -8,6 +8,22 @@ #include #include "TextureEnumBase.h" +/*! + * \class TextureManager + * \brief A manager for loading, caching, and drawing textures. + * + * The `TextureManager` class is responsible for handling texture loading, caching, + * and rendering in the engine. It provides functions to add, load, and draw textures + * from files, as well as manage sprite sheets. + * + * It uses two caches: one for regular textures (`texture_cache`) and one for + * map tile textures (`mapTile_texture_cache`). This allows for efficient texture reuse + * and management across different parts of the game. + * + * \note Textures are identified by an enum class `Textures` which is user-defined. + * Developers are expected to define the texture types in their own implementation. + */ + class TextureManager { public: @@ -21,12 +37,50 @@ class TextureManager } } + /*! + * \brief Adds a single texture to the cache. + * \param texture The texture identifier. + * \param filePath The file path to the texture file. + * + * This function loads the texture from the specified file and stores it in + * the `texture_cache`. If loading the texture fails, an exception is thrown. + */ void addSingleTexture(Textures texture, const char* filePath); + + /*! + * \brief Adds multiple textures to the cache. + * \param textures A map of texture identifiers and corresponding file paths. + * + * This function iterates over the provided map of textures and loads each + * texture using `addSingleTexture`. It allows developers to add several + * textures at once. + */ void addTextures(const std::map& textures); + + /*! + * \brief Loads a texture from the cache. + * \param texture The texture identifier. + * \return A pointer to the `SDL_Texture` if found, or `nullptr` if not found. + * + * This function looks up a texture in the `texture_cache` and returns the + * corresponding `SDL_Texture*`. If the texture is not found, it logs an error + * message and returns `nullptr`. + */ SDL_Texture* loadTexture(Textures texture); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); + /*! + * \brief Loads a map tile texture from the file system and caches it. + * \param path The file path to the texture. + * \return A pointer to the `SDL_Texture` representing the map tile. + * + * This function checks if the map tile texture is already cached. If not, it + * loads the texture from the file system and stores it in the cache. + * + * If loading fails, an exception is thrown with a descriptive error message. + * /todo should not be usable for the developer and only be accessed by the map class + */ SDL_Texture* loadMapTileTexture(const char* path); private: diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index ff8e2fd..3b81ee3 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "GameInternal.h" From 4ead20ecb7a9fb760a928480bff6137f8aaaa89e Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 1 Dec 2024 14:39:45 +0100 Subject: [PATCH 15/42] Cleanup of documentation and refactoring renamed TextureEnumBase.h to Textures.h improved some of the doxygen documentation --- include/SpriteComponent.h | 7 ++++--- include/TextureEnumBase.h | 18 ------------------ include/TextureManager.h | 20 ++++++++------------ include/Textures.h | 14 ++++++++++++++ include/TileComponent.h | 2 +- src/AssetManager.cpp | 2 +- src/TileComponent.cpp | 2 -- 7 files changed, 28 insertions(+), 37 deletions(-) delete mode 100644 include/TextureEnumBase.h create mode 100644 include/Textures.h diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 444663d..fae052f 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -5,7 +5,7 @@ #include #include -#include "TextureEnumBase.h" +#include "Textures.h" #include "AnimationHandler.h" #include "Component.h" #include "Direction.h" @@ -35,8 +35,9 @@ private: int textureXOffset; int textureYOffset; - //should be changed in the future as this is only for the tiles - const char* path; + //might be a better solution as this variable is only used for the loading of the tmx map + //TODO: improve this in the future + const char* path; //empty string if texture has a texture enum value, otherwise the path of the texture public: SpriteComponent(Textures texture, int zIndex); diff --git a/include/TextureEnumBase.h b/include/TextureEnumBase.h deleted file mode 100644 index e9e5d9a..0000000 --- a/include/TextureEnumBase.h +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * \file Textures.h - * \brief Forward declaration of the \c Textures enum class. - * - * This file contains a forward declaration of the \c Textures enum class, which is used as a base - * class for texture identifiers in the engine. It allows developers to define their own set of texture - * types in their own implementation, providing flexibility in texture management within the engine. - * - * \details - * The \c Textures enum class is intended to be implemented by the developer within their own scope. - * This allows for customized texture entries to be defined based on the specific needs of the project. - * The base declaration ensures that the enum class can be referenced and used consistently throughout - * the engine while leaving the details of the texture identifiers up to the implementation. - */ - -#pragma once - -enum class Textures; \ No newline at end of file diff --git a/include/TextureManager.h b/include/TextureManager.h index 8789a2c..24614e5 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -6,7 +6,7 @@ #include #include #include -#include "TextureEnumBase.h" +#include "Textures.h" /*! * \class TextureManager @@ -16,12 +16,8 @@ * and rendering in the engine. It provides functions to add, load, and draw textures * from files, as well as manage sprite sheets. * - * It uses two caches: one for regular textures (`texture_cache`) and one for - * map tile textures (`mapTile_texture_cache`). This allows for efficient texture reuse - * and management across different parts of the game. - * - * \note Textures are identified by an enum class `Textures` which is user-defined. - * Developers are expected to define the texture types in their own implementation. + * \sa \ref Textures "Textures" are used to identify textures within the engine. + * It is expected that they are implemented within the games scope. */ class TextureManager @@ -43,7 +39,7 @@ class TextureManager * \param filePath The file path to the texture file. * * This function loads the texture from the specified file and stores it in - * the `texture_cache`. If loading the texture fails, an exception is thrown. + * a cache. If loading the texture fails, an exception is thrown. */ void addSingleTexture(Textures texture, const char* filePath); @@ -52,8 +48,8 @@ class TextureManager * \param textures A map of texture identifiers and corresponding file paths. * * This function iterates over the provided map of textures and loads each - * texture using `addSingleTexture`. It allows developers to add several - * textures at once. + * texture using `addSingleTexture`. It allows for several + * textures to be added at once. */ void addTextures(const std::map& textures); @@ -62,7 +58,7 @@ class TextureManager * \param texture The texture identifier. * \return A pointer to the `SDL_Texture` if found, or `nullptr` if not found. * - * This function looks up a texture in the `texture_cache` and returns the + * This function looks up a texture within the cache and returns the * corresponding `SDL_Texture*`. If the texture is not found, it logs an error * message and returns `nullptr`. */ @@ -73,7 +69,7 @@ class TextureManager /*! * \brief Loads a map tile texture from the file system and caches it. * \param path The file path to the texture. - * \return A pointer to the `SDL_Texture` representing the map tile. + * \return `SDL_Texture*` representing the map tile. * * This function checks if the map tile texture is already cached. If not, it * loads the texture from the file system and stores it in the cache. diff --git a/include/Textures.h b/include/Textures.h new file mode 100644 index 0000000..eb63dfd --- /dev/null +++ b/include/Textures.h @@ -0,0 +1,14 @@ +#pragma once + +/*! + * \class Textures + * \brief Forward declaration of the \c Textures enum class. + * + * The \c Textures enum class is intended to be implemented within the game scope. + * This allows for customized texture entries to be defined based on the specific needs of the project. + * The base declaration ensures that the enum class can be referenced and used consistently throughout + * the engine while leaving the details of the texture identifiers up to the implementation. + * \sa \ref TextureManager "TextureManager" for how the enum is used. + */ + +enum class Textures; \ No newline at end of file diff --git a/include/TileComponent.h b/include/TileComponent.h index 627bb93..0cff1b8 100644 --- a/include/TileComponent.h +++ b/include/TileComponent.h @@ -6,7 +6,7 @@ #include #include "Component.h" -#include "TextureEnumBase.h" +#include "Textures.h" class SpriteComponent; class TransformComponent; diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 9ac14c1..273e345 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -15,7 +15,7 @@ #include "PowerupComponent.h" #include -#include "TextureEnumBase.h" +#include "Textures.h" AssetManager::AssetManager(Manager* manager) : man(manager) {} diff --git a/src/TileComponent.cpp b/src/TileComponent.cpp index 5f36e2f..324c621 100644 --- a/src/TileComponent.cpp +++ b/src/TileComponent.cpp @@ -5,9 +5,7 @@ #include "Entity.h" #include "TransformComponent.h" #include "SpriteComponent.h" -#include "TileComponent.h" -#include "TextureEnumBase.h" TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict) { From dadf84647056b79825766414d4ddd9afcfae7138 Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 1 Dec 2024 14:51:10 +0100 Subject: [PATCH 16/42] fixed \todo in TextureManager.h --- include/TextureManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/TextureManager.h b/include/TextureManager.h index 24614e5..f1cd30c 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -75,7 +75,7 @@ class TextureManager * loads the texture from the file system and stores it in the cache. * * If loading fails, an exception is thrown with a descriptive error message. - * /todo should not be usable for the developer and only be accessed by the map class + * \todo should not be usable for the developer and only be accessed by the map class */ SDL_Texture* loadMapTileTexture(const char* path); From 2483b759831fb304b92fd81e9fc6f6314f56653f Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sun, 1 Dec 2024 18:41:58 +0100 Subject: [PATCH 17/42] Added config file --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9c283eb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +# allow game dev to overwrite settings +root=false + +[*] +end_of_line = lf +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true \ No newline at end of file From b490e2dc1747b5a0ab8c8f3ff33437bc1e32fd12 Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 1 Dec 2024 20:25:31 +0100 Subject: [PATCH 18/42] removed magic enum and documentation improvements since getName is no longer used from the TileComponent.h we no longer need magic_enum for the enum to string conversion also some minor documentation changes --- .gitmodules | 4 +--- CMakeLists.txt | 3 +-- extern/magic_enum | 1 - include/SpriteComponent.h | 4 ++-- include/TextureManager.h | 2 +- include/TileComponent.h | 9 --------- src/SpriteComponent.cpp | 1 - 7 files changed, 5 insertions(+), 19 deletions(-) delete mode 160000 extern/magic_enum diff --git a/.gitmodules b/.gitmodules index 57f7b27..7426239 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,6 +20,4 @@ [submodule "docs/doxygen-awesome-css"] path = docs/doxygen-awesome-css url = https://github.com/jothepro/doxygen-awesome-css.git -[submodule "extern/magic_enum"] - path = extern/magic_enum - url = https://github.com/Neargye/magic_enum.git + diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f6988c..dbb927e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ 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) -add_subdirectory(extern/magic_enum EXCLUDE_FROM_ALL) + file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) add_library(${PROJECT_NAME} ${SOURCES}) @@ -37,7 +37,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC # should be private when all SDL fu SDL2_image::SDL2_image-static SDL2_mixer::SDL2_mixer-static SDL2_ttf::SDL2_ttf-static - magic_enum::magic_enum tmxlite ) diff --git a/extern/magic_enum b/extern/magic_enum deleted file mode 160000 index a72a053..0000000 --- a/extern/magic_enum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a72a0536c716fdef4f029fb43e1fd7e7b3d9ac9b diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index fae052f..0c84359 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -35,8 +35,8 @@ private: int textureXOffset; int textureYOffset; - //might be a better solution as this variable is only used for the loading of the tmx map - //TODO: improve this in the future + //there should be a better solution as this variable is only used for the loading of the tmx map + //TODO: improve this in the future and also remove it from the scope of the developer const char* path; //empty string if texture has a texture enum value, otherwise the path of the texture public: diff --git a/include/TextureManager.h b/include/TextureManager.h index f1cd30c..d77ad18 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -16,7 +16,7 @@ * and rendering in the engine. It provides functions to add, load, and draw textures * from files, as well as manage sprite sheets. * - * \sa \ref Textures "Textures" are used to identify textures within the engine. + * \sa Textures "Textures" are used to identify textures within the engine. * It is expected that they are implemented within the games scope. */ diff --git a/include/TileComponent.h b/include/TileComponent.h index 0cff1b8..58f92a5 100644 --- a/include/TileComponent.h +++ b/include/TileComponent.h @@ -3,7 +3,6 @@ #include #include #include -#include #include "Component.h" #include "Textures.h" @@ -31,14 +30,6 @@ public: return this->collision; } - std::string getName() { -#ifdef TEXTURE_ENUM_DEFINED - return std::string(magic_enum::enum_name(this->texture)); -#else - return "Undefined Enum"; -#endif - } - private: bool collision; diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 99c7690..80ef7a0 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "AnimationHandler.h" #include "Direction.h" From 58be6b05f0f22f51b2f48c16a4b6d13cfe9d0fc8 Mon Sep 17 00:00:00 2001 From: freezarite Date: Sun, 1 Dec 2024 21:04:45 +0100 Subject: [PATCH 19/42] more documentation changes --- include/SpriteComponent.h | 2 +- include/TextureManager.h | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 0c84359..01056ce 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -37,7 +37,7 @@ private: //there should be a better solution as this variable is only used for the loading of the tmx map //TODO: improve this in the future and also remove it from the scope of the developer - const char* path; //empty string if texture has a texture enum value, otherwise the path of the texture + const char* path; //!< empty string if texture has a texture enum value, otherwise the path of the texture public: SpriteComponent(Textures texture, int zIndex); diff --git a/include/TextureManager.h b/include/TextureManager.h index d77ad18..bd4a087 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -16,7 +16,7 @@ * and rendering in the engine. It provides functions to add, load, and draw textures * from files, as well as manage sprite sheets. * - * \sa Textures "Textures" are used to identify textures within the engine. + * \sa Textures are used to identify textures within the engine. * It is expected that they are implemented within the games scope. */ @@ -37,9 +37,10 @@ class TextureManager * \brief Adds a single texture to the cache. * \param texture The texture identifier. * \param filePath The file path to the texture file. + * \throws std::runtime_error Is thrown if the texture could not be loaded correctly * * This function loads the texture from the specified file and stores it in - * a cache. If loading the texture fails, an exception is thrown. + * a cache. */ void addSingleTexture(Textures texture, const char* filePath); @@ -70,11 +71,11 @@ class TextureManager * \brief Loads a map tile texture from the file system and caches it. * \param path The file path to the texture. * \return `SDL_Texture*` representing the map tile. + * \throws std::runtime_error Is thrown if the texture could not be loaded correctly * * This function checks if the map tile texture is already cached. If not, it * loads the texture from the file system and stores it in the cache. * - * If loading fails, an exception is thrown with a descriptive error message. * \todo should not be usable for the developer and only be accessed by the map class */ SDL_Texture* loadMapTileTexture(const char* path); From 6a0b5197f97aa1aaa4946a91ecf700c6e7730128 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Mon, 2 Dec 2024 21:47:36 +0100 Subject: [PATCH 20/42] Implemented suggested changes --- include/Component.h | 3 ++- src/SoundManager.cpp | 8 ++++---- src/StatEffectsComponent.cpp | 8 +++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/Component.h b/include/Component.h index 5003dc3..8f4a70a 100644 --- a/include/Component.h +++ b/include/Component.h @@ -1,6 +1,7 @@ #pragma once -#include +#include + class Entity; class Component diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 182d616..6775725 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -66,12 +66,12 @@ void SoundManager::playSound(GameInternal* game, std::string sound, bool canOver if(Mix_VolumeChunk(game->assets->getSound(sound), volume) == -1) { - std::cerr << "Error adjusting volume: " /*<< Mix_GetError()*/ << std::endl; + std::cerr << "Error adjusting volume: " << SDL_GetError() << std::endl; } if (Mix_PlayChannel(channel, game->assets->getSound(sound), loops) == -1) { - std::cerr << "Error playing sound '" << sound << "': " /*<< Mix_GetError()*/ << std::endl; + std::cerr << "Error playing sound '" << sound << "': " << SDL_GetError() << std::endl; } } @@ -88,12 +88,12 @@ void SoundManager::playMusic(GameInternal* game, std::string music, int loops, i if(Mix_VolumeMusic(volume) == -1) { - std::cerr << "Error adjusting volume: " /*<< Mix_GetError()*/ << std::endl; + std::cerr << "Error adjusting volume: " << SDL_GetError() << std::endl; } if (Mix_PlayMusic(game->assets->getMusic(music), loops) == -1) { - std::cerr << "Error playing music '" << music << "': " /*<< Mix_GetError()*/ << std::endl; + std::cerr << "Error playing music '" << music << "': " << SDL_GetError() << std::endl; } } diff --git a/src/StatEffectsComponent.cpp b/src/StatEffectsComponent.cpp index 05ab31a..8d4d7ee 100644 --- a/src/StatEffectsComponent.cpp +++ b/src/StatEffectsComponent.cpp @@ -12,12 +12,10 @@ void StatEffectsComponent::update(uint_fast16_t diffTime) { for (int i = 0; i < MAX_STATS; i++) { - if (this->buffs.at(i) <= 0) continue; - if (this->buffs.at(i) - diffTime <= 0) - { + this->buffs.at(i) -= diffTime; + if (this->buffs.at(i) <= 0) { this->resetStatValue((Stats)i); } - this->buffs.at(i) -= diffTime; } } @@ -32,7 +30,7 @@ void StatEffectsComponent::modifyStatValue(Stats stat, int modifier) //modifier switch (stat) { case Stats::MOVEMENT_SPEED: - this->entity->getComponent().modifySpeed(modifier * 60); + this->entity->getComponent().modifySpeed(modifier); break; case Stats::ATTACK_SPEED: // this->entity->getComponent().modifyAtkSpeed(modifier); From 9247b8df8a9f685cb0e92a6dc800227244ff6083 Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 3 Dec 2024 18:17:31 +0100 Subject: [PATCH 21/42] started work on config-system added nlohmann_json library as submodule and to CMakeLists.txt created basic config.json file in root folder created ConfigLoader.h and added basic functionalities to it --- .gitmodules | 3 +++ CMakeLists.txt | 6 +++++- config.json | 3 +++ extern/nlohmann_json | 1 + include/ConfigLoader.h | 24 ++++++++++++++++++++++++ src/ConfigLoader.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 config.json create mode 160000 extern/nlohmann_json create mode 100644 include/ConfigLoader.h create mode 100644 src/ConfigLoader.cpp 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..12d886d 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) +add_subdirectory(extern/nlohmann_json EXCLUDE_FROM_ALL) 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}) @@ -37,6 +40,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC # should be private when all SDL fu SDL3_mixer::SDL3_mixer-static SDL3_ttf::SDL3_ttf-static tmxlite + nlohmann_json::nlohmann_json ) if(CMAKE_BUILD_TYPE MATCHES "Debug") diff --git a/config.json b/config.json new file mode 100644 index 0000000..2aff41b --- /dev/null +++ b/config.json @@ -0,0 +1,3 @@ +{ + "fullscreen": false +} \ 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..d0115a4 --- /dev/null +++ b/include/ConfigLoader.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +using json = nlohmann::json; + +class ConfigLoader { + +public: + ConfigLoader(); + ~ConfigLoader(); + + void init(); + + void setCustomConfig(std::string path); + +private: + json baseConfig; + std::optional customConfig; + json finalConfig; + + json loadConfigFromJSON(const std::string& path); + json mergeConfigs(json baseConfig, json customConfig); // + +ConfigLoader::ConfigLoader() { + baseConfig = loadConfigFromJSON("config.json"); +} + +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(std::string path) { + customConfig.emplace(loadConfigFromJSON(path)); +} + +json ConfigLoader::mergeConfigs(json baseConfig, json customConfig) { + for (auto& entry : customConfig.items()) { + baseConfig[entry.key()] = entry.value(); + } + return baseConfig; +} + + From 5e48f4e34ff4fd963880c08fda5f4540d96b4fdb Mon Sep 17 00:00:00 2001 From: freezarite Date: Fri, 13 Dec 2024 14:36:43 +0100 Subject: [PATCH 22/42] Config now gets read by the GameInternal.cpp Made the process of adding a custom Config file work via a Virtual function within Game.h --- include/ConfigLoader.h | 4 +++- include/Game.h | 1 + src/ConfigLoader.cpp | 11 +++++++++-- src/GameInternal.cpp | 11 +++++++++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/ConfigLoader.h b/include/ConfigLoader.h index d0115a4..8ba9c55 100644 --- a/include/ConfigLoader.h +++ b/include/ConfigLoader.h @@ -12,7 +12,9 @@ public: void init(); - void setCustomConfig(std::string path); + void setCustomConfig(const std::optional& path); + + json getFinalConfig(); private: json baseConfig; diff --git a/include/Game.h b/include/Game.h index 3eb990d..75f6713 100644 --- a/include/Game.h +++ b/include/Game.h @@ -9,6 +9,7 @@ public: virtual void init() = 0; virtual void update(uint_fast16_t diffTime) = 0; + virtual std::optional getConfigFilePath() {return std::nullopt;} GameInternal* gameInternal; //!< \deprecated }; diff --git a/src/ConfigLoader.cpp b/src/ConfigLoader.cpp index 4c8cb04..4620c56 100644 --- a/src/ConfigLoader.cpp +++ b/src/ConfigLoader.cpp @@ -6,6 +6,8 @@ ConfigLoader::ConfigLoader() { baseConfig = loadConfigFromJSON("config.json"); } +ConfigLoader::~ConfigLoader() {} + void ConfigLoader::init() { if (!customConfig.has_value()) { finalConfig = baseConfig; @@ -27,8 +29,8 @@ json ConfigLoader::loadConfigFromJSON(const std::string& path) { } -void ConfigLoader::setCustomConfig(std::string path) { - customConfig.emplace(loadConfigFromJSON(path)); +void ConfigLoader::setCustomConfig(const std::optional& path) { + customConfig = path; } json ConfigLoader::mergeConfigs(json baseConfig, json customConfig) { @@ -38,4 +40,9 @@ json ConfigLoader::mergeConfigs(json baseConfig, json customConfig) { return baseConfig; } +json ConfigLoader::getFinalConfig() { + return finalConfig; +} + + diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 1e4eac3..c1df0be 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -15,6 +15,8 @@ #include +#include "ConfigLoader.h" + GameInternal::GameInternal() : manager(this), renderManager(), @@ -29,13 +31,19 @@ GameInternal::~GameInternal() = default; SDL_AppResult GameInternal::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen) { + this->gameInstance = GameFactory::instance().create(this); + ConfigLoader().setCustomConfig(this->gameInstance->getConfigFilePath()); + ConfigLoader().init(); + + json config = ConfigLoader().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 (config.at("fullscreen")) { flags = SDL_WINDOW_FULLSCREEN; } @@ -95,7 +103,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; From acdbf29896de68c3bffeed9b33b32850028f11ef Mon Sep 17 00:00:00 2001 From: freezarite Date: Mon, 16 Dec 2024 05:47:28 +0100 Subject: [PATCH 23/42] Fixed a bug where the custom json was not loaded correctly Changed base config location to ./engine/config.json to make implementation better for the game-dev --- src/ConfigLoader.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ConfigLoader.cpp b/src/ConfigLoader.cpp index 4620c56..65381f5 100644 --- a/src/ConfigLoader.cpp +++ b/src/ConfigLoader.cpp @@ -3,7 +3,9 @@ #include ConfigLoader::ConfigLoader() { - baseConfig = loadConfigFromJSON("config.json"); + //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() {} @@ -30,7 +32,9 @@ json ConfigLoader::loadConfigFromJSON(const std::string& path) { void ConfigLoader::setCustomConfig(const std::optional& path) { - customConfig = path; + if (path.has_value()) { + customConfig = loadConfigFromJSON(path.value()); + } } json ConfigLoader::mergeConfigs(json baseConfig, json customConfig) { From 691ea06eb0afde281f35c0e92f60c800836396c4 Mon Sep 17 00:00:00 2001 From: freezarite Date: Mon, 16 Dec 2024 06:02:58 +0100 Subject: [PATCH 24/42] Added and implemented some more config options in the GameInternal.cpp. Also removed GameInternal::init() parameters as they are no longer needed --- config.json | 6 +++++- include/GameInternal.h | 2 +- src/GameInternal.cpp | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/config.json b/config.json index 2aff41b..0e0eb80 100644 --- a/config.json +++ b/config.json @@ -1,3 +1,7 @@ { - "fullscreen": false + "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/include/GameInternal.h b/include/GameInternal.h index 7cb3b1f..98c8fd1 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -27,7 +27,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); diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index c1df0be..7d5f5fc 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -29,7 +29,7 @@ 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() { this->gameInstance = GameFactory::instance().create(this); ConfigLoader().setCustomConfig(this->gameInstance->getConfigFilePath()); @@ -60,7 +60,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(config.at("title").get().c_str(), config.at("width"), config.at("height"), flags); if (!window) { std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; @@ -70,7 +70,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(config.at("icon").get().c_str()))) { SDL_SetWindowIcon(window, icon); } From 1f3cf01419be9d378dac53f9760e473117067f37 Mon Sep 17 00:00:00 2001 From: freezarite Date: Mon, 16 Dec 2024 06:08:52 +0100 Subject: [PATCH 25/42] fixed a bug with the implementation of the nlohmann library in the CMakeLists.txt fixed a bug where the config was not loaded correctly in the GameInternal.cpp --- CMakeLists.txt | 3 +-- src/GameInternal.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12d886d..2b44666 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ 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) -add_subdirectory(extern/nlohmann_json EXCLUDE_FROM_ALL) +include_directories(extern/nlohmann_json/include) file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) @@ -40,7 +40,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC # should be private when all SDL fu SDL3_mixer::SDL3_mixer-static SDL3_ttf::SDL3_ttf-static tmxlite - nlohmann_json::nlohmann_json ) if(CMAKE_BUILD_TYPE MATCHES "Debug") diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 7d5f5fc..65619f2 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -31,11 +31,13 @@ GameInternal::~GameInternal() = default; SDL_AppResult GameInternal::init() { - this->gameInstance = GameFactory::instance().create(this); - ConfigLoader().setCustomConfig(this->gameInstance->getConfigFilePath()); - ConfigLoader().init(); + ConfigLoader* loader = new ConfigLoader(); - json config = ConfigLoader().getFinalConfig(); + this->gameInstance = GameFactory::instance().create(this); + loader->setCustomConfig(this->gameInstance->getConfigFilePath()); + loader->init(); + + json config = loader->getFinalConfig(); GameInternal::assets = new AssetManager(&manager); GameInternal::textureManager = new TextureManager(&manager); From 55b60624c4c43204f5ce830c737c722385718eb1 Mon Sep 17 00:00:00 2001 From: freezarite Date: Mon, 16 Dec 2024 06:10:31 +0100 Subject: [PATCH 26/42] added a folder to hold internal assets for the standard config of the engine --- internalAssets/iconImage.bmp | Bin 0 -> 3126 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 internalAssets/iconImage.bmp diff --git a/internalAssets/iconImage.bmp b/internalAssets/iconImage.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6eddbefc55ade778d7ad509e6d00db55652a5cc4 GIT binary patch literal 3126 zcmeH{ze)o^5Qk%}m6fHXPY?t9lDhB&NEsUdOv^pZZ|#1VLJ zsUZzXuj(s{o`TL$d_EruIIAmdfM!&l54WR Date: Mon, 16 Dec 2024 06:21:26 +0100 Subject: [PATCH 27/42] removed no longer used variables in Constants.h updated _Init.cpp to use updated init() function from GameInternal.cpp --- include/Constants.h | 3 --- src/_Init.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/Constants.h b/include/Constants.h index 713f1bd..2c70809 100644 --- a/include/Constants.h +++ b/include/Constants.h @@ -11,9 +11,6 @@ constexpr std::size_t MAX_GROUPS = 32; constexpr std::size_t MAX_STATS = 8; constexpr std::size_t MAX_TEAMS = 8; -constexpr int SCREEN_SIZE_HEIGHT = 640; -constexpr int SCREEN_SIZE_WIDTH = 800; - constexpr int FPS = 60; constexpr int TILE_SIZE = 32; 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) { From abe018f99bf6b19c2d389580b64b247bc3cdbd60 Mon Sep 17 00:00:00 2001 From: freezarite Date: Mon, 16 Dec 2024 13:12:53 +0100 Subject: [PATCH 28/42] fixed some issues stemming from the removal of the window-size constant variables --- include/GameInternal.h | 3 +++ src/AssetManager.cpp | 5 +++-- src/CollisionHandler.cpp | 9 +++++---- src/GameInternal.cpp | 14 +++++++------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/GameInternal.h b/include/GameInternal.h index 98c8fd1..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; @@ -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/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/GameInternal.cpp b/src/GameInternal.cpp index 65619f2..3c55148 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -31,13 +31,13 @@ GameInternal::~GameInternal() = default; SDL_AppResult GameInternal::init() { - ConfigLoader* loader = new ConfigLoader(); + config = new ConfigLoader; this->gameInstance = GameFactory::instance().create(this); - loader->setCustomConfig(this->gameInstance->getConfigFilePath()); - loader->init(); + config->setCustomConfig(this->gameInstance->getConfigFilePath()); + config->init(); - json config = loader->getFinalConfig(); + json finalConfig = config->getFinalConfig(); GameInternal::assets = new AssetManager(&manager); GameInternal::textureManager = new TextureManager(&manager); @@ -45,7 +45,7 @@ SDL_AppResult GameInternal::init() GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer? int flags = 0; - if (config.at("fullscreen")) + if (finalConfig.at("fullscreen")) { flags = SDL_WINDOW_FULLSCREEN; } @@ -62,7 +62,7 @@ SDL_AppResult GameInternal::init() return SDL_APP_FAILURE; } - window = SDL_CreateWindow(config.at("title").get().c_str(), config.at("width"), config.at("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; @@ -72,7 +72,7 @@ SDL_AppResult GameInternal::init() // bad SDL_Surface* icon; - if((icon = SDL_LoadBMP(config.at("icon").get().c_str()))) + if((icon = SDL_LoadBMP(finalConfig.at("icon").get().c_str()))) { SDL_SetWindowIcon(window, icon); } From 91f15671c0cfa6d7ca94a651de712562f17d3389 Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 17 Dec 2024 16:08:28 +0100 Subject: [PATCH 29/42] fixed pull request issues --- CMakeLists.txt | 7 +++---- config.json | 4 ++-- include/ConfigLoader.h | 4 ++-- include/Game.h | 2 +- src/AssetManager.cpp | 4 ++-- src/CollisionHandler.cpp | 8 ++++---- src/ConfigLoader.cpp | 19 +++++++++---------- src/GameInternal.cpp | 8 +++++--- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b44666..b0764f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,13 +24,11 @@ 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) +add_subdirectory(extern/nlohmann_json EXCLUDE_FROM_ALL) file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) -add_library(${PROJECT_NAME} ${SOURCES} - include/ConfigLoader.h - src/ConfigLoader.cpp) +add_library(${PROJECT_NAME} ${SOURCES}) target_include_directories(${PROJECT_NAME} PUBLIC ${ENGINE_INCLUDE_DIR}) @@ -39,6 +37,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC # should be private when all SDL fu SDL3_image::SDL3_image-static SDL3_mixer::SDL3_mixer-static SDL3_ttf::SDL3_ttf-static + nlohmann_json::nlohmann_json tmxlite ) diff --git a/config.json b/config.json index 0e0eb80..e4ee3bf 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "fullscreen": false, "title": "VGG (Very Good Game)", - "height": 100, - "width": 100, + "screen_height": 100, + "screen_width": 100, "icon": "./engine/internalAssets/iconImage.bmp" } \ No newline at end of file diff --git a/include/ConfigLoader.h b/include/ConfigLoader.h index 8ba9c55..d92977e 100644 --- a/include/ConfigLoader.h +++ b/include/ConfigLoader.h @@ -17,8 +17,8 @@ public: json getFinalConfig(); private: - json baseConfig; - std::optional customConfig; + + std::optional customConfigPath; json finalConfig; json loadConfigFromJSON(const std::string& path); diff --git a/include/Game.h b/include/Game.h index 75f6713..84e3b8e 100644 --- a/include/Game.h +++ b/include/Game.h @@ -9,7 +9,7 @@ public: virtual void init() = 0; virtual void update(uint_fast16_t diffTime) = 0; - virtual std::optional getConfigFilePath() {return std::nullopt;} + virtual std::optional setConfigFilePath() {return std::nullopt;} GameInternal* gameInternal; //!< \deprecated }; diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 553617a..75e78ec 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -77,8 +77,8 @@ Vector2D AssetManager::calculateSpawnPosition() { SDL_Rect spawnRect; spawnRect.h = spawnRect.w = 32; - spawnRect.x = rand() % (VEGO_Game().config->getFinalConfig().at("width").get() - spawnRect.w); - spawnRect.y = rand() % (VEGO_Game().config->getFinalConfig().at("height").get() - spawnRect.h); + spawnRect.x = rand() % (VEGO_Game().config->getFinalConfig().at("screen_width").get() - spawnRect.w); + spawnRect.y = rand() % (VEGO_Game().config->getFinalConfig().at("screen_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 0177728..d153d0c 100644 --- a/src/CollisionHandler.cpp +++ b/src/CollisionHandler.cpp @@ -67,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 > VEGO_Game().config->getFinalConfig().at("width")) { + collider->x + posMod.x > VEGO_Game().config->getFinalConfig().at("screen_width")) { intersections.set((size_t) Direction::LEFT); } if (collider->x + collider->w + posMod.x < 0 || - collider->x + collider->w + posMod.x > VEGO_Game().config->getFinalConfig().at("width")) + collider->x + collider->w + posMod.x > VEGO_Game().config->getFinalConfig().at("screen_width")) intersections.set((size_t) Direction::RIGHT); if (collider->y + posMod.y < 0 || - collider->y + posMod.y > VEGO_Game().config->getFinalConfig().at("height")) + collider->y + posMod.y > VEGO_Game().config->getFinalConfig().at("screen_height")) intersections.set((size_t) Direction::UP); if (collider->y + collider->h + posMod.y < 0 || - collider->y + collider->h + posMod.y > VEGO_Game().config->getFinalConfig().at("height")) + collider->y + collider->h + posMod.y > VEGO_Game().config->getFinalConfig().at("screen_height")) intersections.set((size_t) Direction::DOWN); return intersections; diff --git a/src/ConfigLoader.cpp b/src/ConfigLoader.cpp index 65381f5..7b244e4 100644 --- a/src/ConfigLoader.cpp +++ b/src/ConfigLoader.cpp @@ -2,20 +2,21 @@ #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() {} ConfigLoader::~ConfigLoader() {} void ConfigLoader::init() { - if (!customConfig.has_value()) { + //TODO: look into adaptive paths for better handling as this requires the implemented game + // to have ./engine in the root folder + const json baseConfig = loadConfigFromJSON("./engine/config.json"); + + if (!customConfigPath.has_value()) { finalConfig = baseConfig; return; } - finalConfig = mergeConfigs(baseConfig, customConfig.value()); + + finalConfig = mergeConfigs(baseConfig, loadConfigFromJSON(customConfigPath.value())); } json ConfigLoader::loadConfigFromJSON(const std::string& path) { @@ -32,9 +33,7 @@ json ConfigLoader::loadConfigFromJSON(const std::string& path) { void ConfigLoader::setCustomConfig(const std::optional& path) { - if (path.has_value()) { - customConfig = loadConfigFromJSON(path.value()); - } + customConfigPath = path; } json ConfigLoader::mergeConfigs(json baseConfig, json customConfig) { diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 3c55148..77becb6 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -31,10 +31,10 @@ GameInternal::~GameInternal() = default; SDL_AppResult GameInternal::init() { - config = new ConfigLoader; + config = new ConfigLoader(); this->gameInstance = GameFactory::instance().create(this); - config->setCustomConfig(this->gameInstance->getConfigFilePath()); + config->setCustomConfig(this->gameInstance->setConfigFilePath()); config->init(); json finalConfig = config->getFinalConfig(); @@ -62,7 +62,9 @@ SDL_AppResult GameInternal::init() return SDL_APP_FAILURE; } - window = SDL_CreateWindow(finalConfig.at("title").get().c_str(), finalConfig.at("width"), finalConfig.at("height"), flags); + window = SDL_CreateWindow(finalConfig.at("title").get().c_str(), + finalConfig.at("screen_width"), finalConfig.at("screen_height"), flags); + if (!window) { std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; From 201b5c8b5dfd16da0470b3dae2b4df963b193959 Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 14 Jan 2025 19:27:56 +0100 Subject: [PATCH 30/42] added documentation --- include/ConfigLoader.h | 40 ++++++++++++++++++++++++++++++++++++++-- include/Game.h | 9 +++++++++ src/ConfigLoader.cpp | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/include/ConfigLoader.h b/include/ConfigLoader.h index d92977e..6262f2b 100644 --- a/include/ConfigLoader.h +++ b/include/ConfigLoader.h @@ -4,16 +4,52 @@ using json = nlohmann::json; +/*! + * \class ConfigLoader + * \brief Enables configuration of specific engine variables via a custom JSON file. + * + * The Config loader is responsible to handling customization for engine parameters like the + * window icon, window title, ... through json files. + * + * It includes a standard config file and the option to add a custom one by overwriting the setConfigFilePath() + * function within the implementation of the \ref Game class. Those files get merged, with a priorization on + * the parameters set within the custom config file. + * + * + * The currently available config parameters with their default values are: + * \include ../config.json + * + */ + class ConfigLoader { public: ConfigLoader(); ~ConfigLoader(); + /*! + * \brief Creates the final config for the engine + * + * Loads the default config and then creates the final config by either merging + * (if the custom config has been set) or by implementing the standard config (if no custom + * config was set). + * + * \private + */ void init(); - + /*! + * \brief Sets the customConfigPath variable + * + * \param path optional variable that should include the path to the custom config JSON file + * + * \private + */ void setCustomConfig(const std::optional& path); - + /*! + * \brief Gets final configuration + * \return `json` variable containing the final config + * \private + */ json getFinalConfig(); private: diff --git a/include/Game.h b/include/Game.h index 84e3b8e..d4a8e8a 100644 --- a/include/Game.h +++ b/include/Game.h @@ -9,6 +9,15 @@ public: virtual void init() = 0; virtual void update(uint_fast16_t diffTime) = 0; + + /*! + * \brief Sets the path for a custom config file. + * + * Virtual function to be overwritten in the implementation to return the path of a custom config JSON file. + * \sa Layout of the config file is shown in ConfigLoader + * + * \return std::optional + */ virtual std::optional setConfigFilePath() {return std::nullopt;} GameInternal* gameInternal; //!< \deprecated diff --git a/src/ConfigLoader.cpp b/src/ConfigLoader.cpp index 7b244e4..9e9911c 100644 --- a/src/ConfigLoader.cpp +++ b/src/ConfigLoader.cpp @@ -8,7 +8,7 @@ ConfigLoader::~ConfigLoader() {} void ConfigLoader::init() { //TODO: look into adaptive paths for better handling as this requires the implemented game - // to have ./engine in the root folder + // to have ./engine in the root folder (very low prio) const json baseConfig = loadConfigFromJSON("./engine/config.json"); if (!customConfigPath.has_value()) { From 9195b19bdbec792f583306aa1578b024b49525cd Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 14 Jan 2025 21:40:00 +0100 Subject: [PATCH 31/42] changed default width and height in config.json --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index e4ee3bf..33a7d13 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "fullscreen": false, "title": "VGG (Very Good Game)", - "screen_height": 100, - "screen_width": 100, + "screen_height": 600, + "screen_width": 800, "icon": "./engine/internalAssets/iconImage.bmp" } \ No newline at end of file From 044d957106fc7c3e396637162942c9f47d8bfeb4 Mon Sep 17 00:00:00 2001 From: Nimac0 Date: Sun, 26 Jan 2025 22:36:50 +0100 Subject: [PATCH 32/42] feat: data and stats - reimplemented/unhardcoded stateffects - reimplemented/unhardcoded pickupables - implemented datacomponent - some minor cleanup --- include/DataComponent.h | 26 ++++++++++++++++ include/Entity.h | 2 +- include/StatEffectsComponent.h | 18 +++++------- include/TransformComponent.h | 20 +++++-------- src/AssetManager.cpp | 10 ------- src/StatEffectsComponent.cpp | 54 ++++++++-------------------------- src/TransformComponent.cpp | 20 ++++--------- 7 files changed, 61 insertions(+), 89 deletions(-) create mode 100644 include/DataComponent.h diff --git a/include/DataComponent.h b/include/DataComponent.h new file mode 100644 index 0000000..8d514bf --- /dev/null +++ b/include/DataComponent.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include "Component.h" + +class DataComponent : public Component +{ +public: + DataComponent() {}; + ~DataComponent() {}; + template + void setEntry(const std::string& key, const T& value) { dataMap.insert_or_assign(key, value); } + + template + std::optional getEntry(std::string key) const { + if (!this->dataMap.contains(key)) return std::nullopt; + const std::any& value = this->dataMap.at(key); + if (value.type() != typeid(T)) { return std::nullopt; } + return std::any_cast(value); + } +private: + std::map dataMap; +}; \ No newline at end of file diff --git a/include/Entity.h b/include/Entity.h index 196a105..b609bf1 100644 --- a/include/Entity.h +++ b/include/Entity.h @@ -77,7 +77,7 @@ public: return *c; }; - template T& getComponent() const + template T& getComponent() const //!< \todo: rewrite to use optionals { auto ptr(componentArray[getComponentTypeID()]); return *static_cast(ptr); diff --git a/include/StatEffectsComponent.h b/include/StatEffectsComponent.h index bc93f2b..8c438f9 100644 --- a/include/StatEffectsComponent.h +++ b/include/StatEffectsComponent.h @@ -3,11 +3,13 @@ #include "Constants.h" #include #include +#include -enum class Stats -{ - MOVEMENT_SPEED, - ATTACK_SPEED +// This acts as a manager for the lifetime of a stateffect +struct StatEffect { + uint32_t duration; + std::function resetFunction; + uint32_t startTime; }; class StatEffectsComponent : public Component{ @@ -17,12 +19,8 @@ public: void init() override; void update() override; - - void modifyStatDur(Stats stat, int duration, int value); - - void modifyStatValue(Stats stat, int modifier); - void resetStatValue(Stats stat); + void addEffect(uint32_t duration, std::function resetFunction); private: - std::array buffs = { 0 }; + std::vector effects = {}; }; \ No newline at end of file diff --git a/include/TransformComponent.h b/include/TransformComponent.h index bfe3160..6b68b45 100644 --- a/include/TransformComponent.h +++ b/include/TransformComponent.h @@ -3,6 +3,7 @@ #include "Component.h" #include "Vector2D.h" #include "Constants.h" +#include "DataComponent.h" class TransformComponent : public Component { @@ -14,21 +15,14 @@ public: int width = 32; int scale = 1; - int getSpeed() { return speed + speedMod; }; - void resetSpeedMod() { speedMod = 0; }; - - TransformComponent(); - explicit TransformComponent(int scale); - TransformComponent(float x, float y); - TransformComponent(float x, float y, int scale); - TransformComponent(float x, float y, int w, int h, int scale); + explicit TransformComponent(int scale = 1); + TransformComponent(float x, float y, int scale = 1); + TransformComponent(float x, float y, int w, int h, int scale = 1); void init() override; void update() override; - void setPositionAfterCollision(Vector2D& positionChange); - void modifySpeed(int8_t modifier); + + int getSpeed(); -private: - int speed = 3; - int speedMod = 0; + void setPositionAfterCollision(Vector2D& positionChange); }; diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 25ce8ad..db3d1b8 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -46,16 +46,6 @@ Mix_Music* AssetManager::getMusic(std::string id) return music.at(id); } -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner) { - - auto& projectile(man->addEntity()); - projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects - projectile.addComponent(texturePath, 4); - projectile.addComponent(range, speed, velocity, owner); - projectile.addComponent("projectile", 0.6f); - projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE); -} - void AssetManager::createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath) { auto& powerups(man->addEntity()); diff --git a/src/StatEffectsComponent.cpp b/src/StatEffectsComponent.cpp index c66e206..2598176 100644 --- a/src/StatEffectsComponent.cpp +++ b/src/StatEffectsComponent.cpp @@ -1,7 +1,6 @@ #include "StatEffectsComponent.h" #include "Entity.h" #include "TransformComponent.h" -// #include "KeyboardController.h" #include #include @@ -10,47 +9,20 @@ void StatEffectsComponent::init() void StatEffectsComponent::update() { - for (int i = 0; i < MAX_STATS; i++) - { - if (this->buffs.at(i) == 0) continue; - if (this->buffs.at(i) - 1 == 0) - { - this->resetStatValue((Stats)i); + uint32_t currentTime = SDL_GetTicks(); + for (auto it = effects.begin(); it != effects.end(); ) { + uint32_t elapsedTime = currentTime - it->startTime; + + if (elapsedTime >= it->duration) { + it->resetFunction(); + it = effects.erase(it); + continue; } - this->buffs.at(i) -= 1; - } + it++; + } } -void StatEffectsComponent::modifyStatDur(Stats stat, int duration, int value) -{ - if(this->buffs.at((uint8_t)stat) == 0) this->modifyStatValue(stat, value); - this->buffs.at((uint8_t)stat) += duration; -} - -void StatEffectsComponent::modifyStatValue(Stats stat, int modifier) //modifier is basically there so the modifyfuncs in the components know if stats should be increased or decreased -{ - switch (stat) - { - case Stats::MOVEMENT_SPEED: - this->entity->getComponent().modifySpeed(modifier); - break; - case Stats::ATTACK_SPEED: - // this->entity->getComponent().modifyAtkSpeed(modifier); - break; - default: break; - } -} - -void StatEffectsComponent::resetStatValue(Stats stat) -{ - switch (stat) - { - case Stats::MOVEMENT_SPEED: - this->entity->getComponent().resetSpeedMod(); - break; - case Stats::ATTACK_SPEED: - // this->entity->getComponent().resetAtkSpeedMod(); - break; - default: break; - } +void StatEffectsComponent::addEffect(uint32_t duration, std::function resetFunction) { + uint32_t startTime = SDL_GetTicks(); + effects.push_back({duration, resetFunction, startTime}); } \ No newline at end of file diff --git a/src/TransformComponent.cpp b/src/TransformComponent.cpp index 3854176..c845166 100644 --- a/src/TransformComponent.cpp +++ b/src/TransformComponent.cpp @@ -9,26 +9,16 @@ #include #include #include +#include #include "SoundManager.h" -TransformComponent::TransformComponent() -{ - position.zero(); -} - TransformComponent::TransformComponent(int scale) { position.zero(); this->scale = scale; } -TransformComponent::TransformComponent(float x, float y) -{ - this->position.x = x; - this->position.y = y; -} - TransformComponent::TransformComponent(float x, float y, int scale) { this->position.x = x; @@ -65,9 +55,11 @@ void TransformComponent::update() position += positionChange; } -void TransformComponent::modifySpeed(int8_t modifier) -{ - this->speedMod += modifier; +int TransformComponent::getSpeed() +{ + return (this->entity->hasComponent() + ? this->entity->getComponent().getEntry("speed").value_or(0) + : 0); } void TransformComponent::setPositionAfterCollision(Vector2D& positionChange) From 9bb9d0fbcc4221750eae3115ae4b8ac9be6e1c97 Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 28 Jan 2025 19:08:05 +0100 Subject: [PATCH 33/42] removed maps regarding music and sound effects from the AssetManager reworked SoundManager to use enum classes as keys in its maps and to no longer use the AssetManager added possibility to set sound effect of projectiles when creating them (was hard coded) --- include/AssetManager.h | 13 +----- include/BackgroundMusic.h | 3 ++ include/ProjectileComponent.h | 7 ++- include/SoundEffects.h | 3 ++ include/SoundManager.h | 33 ++++++++++----- src/AssetManager.cpp | 23 +--------- src/ProjectileComponent.cpp | 2 +- src/SoundManager.cpp | 80 +++++++++++++++++++++++++++++------ 8 files changed, 106 insertions(+), 58 deletions(-) create mode 100644 include/BackgroundMusic.h create mode 100644 include/SoundEffects.h diff --git a/include/AssetManager.h b/include/AssetManager.h index a5f635f..eb4d104 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -6,6 +6,7 @@ #include #include "Entity.h" +#include "SoundEffects.h" class Vector2D; class Manager; @@ -24,24 +25,14 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner); + void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner, SoundEffects soundEffect); void createPowerup(Vector2D pos, std::function pickupFunc, Textures texture); Vector2D calculateSpawnPosition(); PowerupType calculateType(); - // sound management - void addSoundEffect(std::string id, const char* path); - - void addMusic(std::string id, const char* path); - - Mix_Chunk* getSound(std::string id); - Mix_Music* getMusic(std::string id); - private: Manager* man; - std::map soundEffects; - std::map music; }; diff --git a/include/BackgroundMusic.h b/include/BackgroundMusic.h new file mode 100644 index 0000000..48516a4 --- /dev/null +++ b/include/BackgroundMusic.h @@ -0,0 +1,3 @@ +#pragma once + +enum class BackgroundMusic; diff --git a/include/ProjectileComponent.h b/include/ProjectileComponent.h index da67ff6..d9f5071 100644 --- a/include/ProjectileComponent.h +++ b/include/ProjectileComponent.h @@ -3,6 +3,7 @@ #include "Component.h" #include "Vector2D.h" #include "Constants.h" +#include "SoundEffects.h" class TransformComponent; @@ -11,8 +12,8 @@ class ProjectileComponent : public Component //can maybe be split in separate .cpp file public: - ProjectileComponent(int range, int speed, Vector2D direction, Entity* owner) - : range(range), speed(speed), direction(direction), owner(owner) {} + ProjectileComponent(int range, int speed, Vector2D direction, Entity* owner, SoundEffects soundEffect) + : range(range), speed(speed), direction(direction), owner(owner), soundEffect(soundEffect) {} ~ProjectileComponent() {} void init() override; @@ -28,4 +29,6 @@ private: Entity* owner = nullptr; Vector2D direction; + + SoundEffects soundEffect; }; \ No newline at end of file diff --git a/include/SoundEffects.h b/include/SoundEffects.h new file mode 100644 index 0000000..609b9a5 --- /dev/null +++ b/include/SoundEffects.h @@ -0,0 +1,3 @@ +#pragma once + +enum class SoundEffects; diff --git a/include/SoundManager.h b/include/SoundManager.h index 38a6b2c..a4b0594 100644 --- a/include/SoundManager.h +++ b/include/SoundManager.h @@ -6,6 +6,8 @@ #include "ECS.h" #include "TextureManager.h" +#include "BackgroundMusic.h" +#include "SoundEffects.h" class GameInternal; @@ -17,8 +19,12 @@ class GameInternal; */ class SoundManager { + public: - SoundManager() {} + + SoundManager() { + this_instance = this; + } ~SoundManager() { for (auto& it : this->sound_cache) { Mix_FreeChunk(it.second); @@ -32,35 +38,32 @@ class SoundManager SoundManager(SoundManager const&) = delete; void operator=(SoundManager const&) = delete; - std::map music_cache; - std::map sound_cache; - - /*! + /* * \brief Loads music from a file (mp3) * \returns a pointer to Mix_Music * \sa AssetManager::AddMusic(std::string id, const char* path) - */ + Mix_Music* loadMusic(const char* fileName); /*! * \brief Loads sound effects from a file (wav) * \returns a pointer to Mix_Chunk * \sa AssetManager::AddSound(std::string id, const char* path) - */ - Mix_Chunk* loadSound(const char* fileName); + Mix_Chunk* loadSound(const char* fileName); + */ /*! * \brief Handles playing of sound effects * * Handles if sounds can overlap, how often they can loop, as well as the volume at which the specified sound effect should play * and on which channel the soundeffect should play. */ - static void playSound(GameInternal* game, std::string sound, bool canOverlap, int loops, int volume, int channel); + static void playSound(SoundEffects sound, bool canOverlap, int loops, int volume, int channel); /*! * \brief Handles playing of music * * Handles how often track can loop, as well as the volume at which the specified track should play and if it fades in. */ - static void playMusic(GameInternal* game, std::string sound, int loops, int volume, int ms); + static void playMusic(BackgroundMusic sound, int loops, int volume, int ms); static void setSoundVolume(int volume, int channel); //!< Volume handling for sound effects (either all or on a specific channel) static void setMusicVolume(int volume); //!< Volume handling for music track @@ -73,5 +76,15 @@ class SoundManager static void fadeOutMusic(int ms); //!< Handles fading out a music track + static void addSingleSoundEffect(SoundEffects soundEffect, const char* path); + static void addSoundEffects(const std::map &effects); + static void addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char* path); + static void addBackgroundMusic(const std::map &backgroundMusic); + + private: + + std::map music_cache; + std::map sound_cache; + static SoundManager* this_instance; }; \ No newline at end of file diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 75e78ec..a7789fc 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -22,32 +22,13 @@ AssetManager::AssetManager(Manager* manager) : man(manager) {} AssetManager::~AssetManager() {} -void AssetManager::addSoundEffect(std::string id, const char* path) -{ - soundEffects.emplace(id, this->man->getGame()->soundManager->loadSound(path)); -} -void AssetManager::addMusic(std::string id, const char* path) -{ - music.emplace(id, this->man->getGame()->soundManager->loadMusic(path)); -} - - -Mix_Chunk* AssetManager::getSound(std::string id) { - return soundEffects.at(id); -} - -Mix_Music* AssetManager::getMusic(std::string id) -{ - return music.at(id); -} - -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner) { +void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner, SoundEffects soundEffect) { auto& projectile(man->addEntity()); projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects projectile.addComponent(textureEnum, 4); - projectile.addComponent(range, speed, velocity, owner); + projectile.addComponent(range, speed, velocity, owner, soundEffect); projectile.addComponent("projectile", 0.6f); projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE); } diff --git a/src/ProjectileComponent.cpp b/src/ProjectileComponent.cpp index e1df015..3f5f13c 100644 --- a/src/ProjectileComponent.cpp +++ b/src/ProjectileComponent.cpp @@ -14,7 +14,7 @@ void ProjectileComponent::init() { transformComponent = &entity->getComponent(); transformComponent->direction = direction; - SoundManager::playSound(this->entity->getManager().getGame(), "throw_egg", true, PLAY_ONCE, MAX_VOLUME, -1); + SoundManager::playSound(this->soundEffect, true, PLAY_ONCE, MAX_VOLUME, -1); } void ProjectileComponent::update(uint_fast16_t diffTime) diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 6775725..15475f4 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -8,9 +8,10 @@ #include "GameInternal.h" #include "AssetManager.h" +/* Mix_Music* SoundManager::loadMusic(const char* fileName) { - auto it = this->music_cache.find(fileName); + //auto it = this->music_cache.find(fileName); if (it != this->music_cache.end()) { return it->second; @@ -48,14 +49,21 @@ Mix_Chunk* SoundManager::loadSound(const char* fileName) return sound; } -void SoundManager::playSound(GameInternal* game, std::string sound, bool canOverlap, int loops, int volume, int channel) +*/ + +void SoundManager::playSound(SoundEffects sound, bool canOverlap, int loops, int volume, int channel) { + if (!this_instance->sound_cache.contains(sound)) { + std::cerr << "Error playing Sound-Effect: sound effect not found" << std::endl; + return; + } + if(!canOverlap) { // dev needs to specify a channel for this check to work, if they set it to -1 and let sdl pick the first available // channel mix_getchunk() won't work if (Mix_Playing(channel) != 0 && - Mix_GetChunk(channel) == game->assets->getSound(sound) && + Mix_GetChunk(channel) == this_instance->sound_cache.at(sound) && channel != -1) { return; @@ -64,25 +72,30 @@ void SoundManager::playSound(GameInternal* game, std::string sound, bool canOver Mix_HaltChannel(channel); } - if(Mix_VolumeChunk(game->assets->getSound(sound), volume) == -1) + if(Mix_VolumeChunk(this_instance->sound_cache.at(sound), volume) == -1) { std::cerr << "Error adjusting volume: " << SDL_GetError() << std::endl; } - if (Mix_PlayChannel(channel, game->assets->getSound(sound), loops) == -1) + if (Mix_PlayChannel(channel, this_instance->sound_cache.at(sound), loops) == -1) { - std::cerr << "Error playing sound '" << sound << "': " << SDL_GetError() << std::endl; + std::cerr << "Error playing sound " << ": " << SDL_GetError() << std::endl; } } -void SoundManager::playMusic(GameInternal* game, std::string music, int loops, int volume, int ms) +void SoundManager::playMusic(BackgroundMusic music, int loops, int volume, int ms) { + if (!this_instance->music_cache.contains(music)) { + std::cerr << "Error playing music: music not found" << std::endl; + return; + } + if (Mix_PlayingMusic() != 0 || Mix_Fading() == Mix_Fading::MIX_FADING_IN) return; if(ms > 0) { - Mix_FadeInMusic(game->assets->getMusic(music), loops, ms); + Mix_FadeInMusic(this_instance->music_cache.at(music), loops, ms); return; } @@ -90,11 +103,6 @@ void SoundManager::playMusic(GameInternal* game, std::string music, int loops, i { std::cerr << "Error adjusting volume: " << SDL_GetError() << std::endl; } - - if (Mix_PlayMusic(game->assets->getMusic(music), loops) == -1) - { - std::cerr << "Error playing music '" << music << "': " << SDL_GetError() << std::endl; - } } void SoundManager::setSoundVolume(int volume, int channel) @@ -134,3 +142,49 @@ void SoundManager::fadeOutMusic(int ms) Mix_FadeOutMusic(ms); } + +void SoundManager::addSingleSoundEffect(SoundEffects soundEffect, const char *path) { + if (this_instance->sound_cache.contains(soundEffect)) { + std::cerr << "Error when adding Sound-Effect: sound-effect with that key already in cache" << std::endl; + return; + } + + Mix_Chunk* sound = Mix_LoadWAV(path); + + if (sound == nullptr) { + std::cerr << "Error when loading Sound-Effect: could not load sound effect from " << path << std::endl; + return; + } + + this_instance->sound_cache.emplace(soundEffect, sound); +} + +void SoundManager::addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char *path) { + if (this_instance->music_cache.contains(backgroundMusic)) { + std::cerr << "Error when adding Sound-Effect: sound-effect with that key already in cache" << std::endl; + return; + } + + Mix_Music* music = Mix_LoadMUS(path); + + if (music == nullptr) { + std::cerr << "Error when loading Sound-Effect: could not load sound effect from " << path << std::endl; + return; + } + + this_instance->music_cache.emplace(backgroundMusic, music); +} + +void SoundManager::addSoundEffects(const std::map &effects) { + for (auto effect : effects) + addSingleSoundEffect(effect.first, effect.second); +} + +void SoundManager::addBackgroundMusic(const std::map &backgroundMusic) { + for (auto track : backgroundMusic) + addSingleBackgroundMusic(track.first, track.second); +} + + + + From 007538f760b67a644cbe4ac18fb00ec8f8844aeb Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 28 Jan 2025 19:31:54 +0100 Subject: [PATCH 34/42] added getInstance method to soundmanager --- include/SoundManager.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/SoundManager.h b/include/SoundManager.h index a4b0594..922f67f 100644 --- a/include/SoundManager.h +++ b/include/SoundManager.h @@ -81,6 +81,10 @@ class SoundManager static void addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char* path); static void addBackgroundMusic(const std::map &backgroundMusic); + static SoundManager* getInstance() { + return this_instance; + } + private: From e215fbd5b67f44957d85be11ec5f9ac9a0ff0f36 Mon Sep 17 00:00:00 2001 From: freezarite Date: Tue, 28 Jan 2025 19:40:14 +0100 Subject: [PATCH 35/42] instance changes in constructor and .cpp file for SoundManager --- include/SoundManager.h | 7 ++++++- src/SoundManager.cpp | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/SoundManager.h b/include/SoundManager.h index 922f67f..de7cd47 100644 --- a/include/SoundManager.h +++ b/include/SoundManager.h @@ -23,7 +23,12 @@ class SoundManager public: SoundManager() { - this_instance = this; + if (this_instance == nullptr) { + this_instance = this; + } + else { + throw std::runtime_error("SoundManager instance already exists!"); + } } ~SoundManager() { for (auto& it : this->sound_cache) { diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 15475f4..fb61796 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -185,6 +185,8 @@ void SoundManager::addBackgroundMusic(const std::map Date: Tue, 28 Jan 2025 21:50:48 +0100 Subject: [PATCH 36/42] pr stuff --- include/SoundManager.h | 16 +++++++++++++--- src/SoundManager.cpp | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/SoundManager.h b/include/SoundManager.h index de7cd47..22d1c71 100644 --- a/include/SoundManager.h +++ b/include/SoundManager.h @@ -68,7 +68,7 @@ class SoundManager * * Handles how often track can loop, as well as the volume at which the specified track should play and if it fades in. */ - static void playMusic(BackgroundMusic sound, int loops, int volume, int ms); + static void playMusic(BackgroundMusic sound, int loops, int volume, int milliseconds); static void setSoundVolume(int volume, int channel); //!< Volume handling for sound effects (either all or on a specific channel) static void setMusicVolume(int volume); //!< Volume handling for music track @@ -81,9 +81,16 @@ class SoundManager static void fadeOutMusic(int ms); //!< Handles fading out a music track - static void addSingleSoundEffect(SoundEffects soundEffect, const char* path); + /*! + * \brief Initializes sound-effects and adds them to a cache + * + */ static void addSoundEffects(const std::map &effects); - static void addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char* path); + + /*! + * \brief Initializes background-music and adds them to a cache + * + */ static void addBackgroundMusic(const std::map &backgroundMusic); static SoundManager* getInstance() { @@ -96,4 +103,7 @@ class SoundManager std::map music_cache; std::map sound_cache; static SoundManager* this_instance; + + static void addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char* path); + static void addSingleSoundEffect(SoundEffects soundEffect, const char* path); }; \ No newline at end of file diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index fb61796..80c5567 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -83,7 +83,7 @@ void SoundManager::playSound(SoundEffects sound, bool canOverlap, int loops, int } } -void SoundManager::playMusic(BackgroundMusic music, int loops, int volume, int ms) +void SoundManager::playMusic(BackgroundMusic music, int loops, int volume, int milliseconds) { if (!this_instance->music_cache.contains(music)) { std::cerr << "Error playing music: music not found" << std::endl; @@ -93,9 +93,9 @@ void SoundManager::playMusic(BackgroundMusic music, int loops, int volume, int m if (Mix_PlayingMusic() != 0 || Mix_Fading() == Mix_Fading::MIX_FADING_IN) return; - if(ms > 0) + if(milliseconds > 0) { - Mix_FadeInMusic(this_instance->music_cache.at(music), loops, ms); + Mix_FadeInMusic(this_instance->music_cache.at(music), loops, milliseconds); return; } From eba3cdb6c8429c9de476ed4a3aa9cced0418685e Mon Sep 17 00:00:00 2001 From: Nimac0 Date: Tue, 28 Jan 2025 22:33:07 +0100 Subject: [PATCH 37/42] doc: add docu - datacomponent - stateffectcomponent - powerupcomponent --- include/AssetManager.h | 1 - include/DataComponent.h | 12 ++++++++++++ include/PowerupComponent.h | 4 ++++ include/StatEffectsComponent.h | 13 ++++++++++--- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/AssetManager.h b/include/AssetManager.h index 1d3c97a..1ba04c9 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -24,7 +24,6 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner); void createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath); Vector2D calculateSpawnPosition(); diff --git a/include/DataComponent.h b/include/DataComponent.h index 8d514bf..805fd30 100644 --- a/include/DataComponent.h +++ b/include/DataComponent.h @@ -11,9 +11,21 @@ class DataComponent : public Component public: DataComponent() {}; ~DataComponent() {}; + /** + * @brief Set a key-value pair of any type in the data map + * @details e.g. setEntry("speed", 180); in this case the key is "speed" and the value is set to an integer of 180 + * @param key The name to store the value under + * @param value The value to store of type T + */ template void setEntry(const std::string& key, const T& value) { dataMap.insert_or_assign(key, value); } + /** + * @brief Get a value of type T from the data map + * @details e.g. getEntry("speed"); in this case the key is "speed" and the value is returned as an integer + * @param key The name to retrieve the value from + * @return An optional of type T containing the value if it exists and matches in typeid, otherwise std::nullopt + */ template std::optional getEntry(std::string key) const { if (!this->dataMap.contains(key)) return std::nullopt; diff --git a/include/PowerupComponent.h b/include/PowerupComponent.h index 53f365b..2e58880 100644 --- a/include/PowerupComponent.h +++ b/include/PowerupComponent.h @@ -6,6 +6,10 @@ class PowerupComponent : public Component { public: + /** + * @brief Construct a new Powerup Component object + * @param func The function to be called when the powerup is picked up + */ PowerupComponent(std::function func); ~PowerupComponent() {}; diff --git a/include/StatEffectsComponent.h b/include/StatEffectsComponent.h index 8c438f9..356d417 100644 --- a/include/StatEffectsComponent.h +++ b/include/StatEffectsComponent.h @@ -5,10 +5,12 @@ #include #include -// This acts as a manager for the lifetime of a stateffect +/** + * @brief Struct to hold the duration, reset function and start time of a stat effect + */ struct StatEffect { - uint32_t duration; - std::function resetFunction; + uint32_t duration; //!< Duration of the effect in milliseconds + std::function resetFunction; //!< Function to reset the effect, will be called on expiry of duration uint32_t startTime; }; @@ -19,6 +21,11 @@ public: void init() override; void update() override; + /** + * @brief Add a stat effect to the entity + * @param duration The duration of the effect in milliseconds + * @param resetFunction The function to reset the effect, will be called on expiry of duration + */ void addEffect(uint32_t duration, std::function resetFunction); private: From d66d860cdcca10ba0b9390927831fe77d68466dc Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Fri, 21 Mar 2025 16:35:03 +0100 Subject: [PATCH 38/42] Implemented event manager --- extern/SDL | 2 +- include/EventListener.h | 11 +++++++++++ include/EventManager.h | 18 ++++++++++++++++++ include/GameInternal.h | 5 +++++ include/VEGO_Event.h | 5 +++++ src/EventManager.cpp | 33 +++++++++++++++++++++++++++++++++ src/GameInternal.cpp | 9 +++++++++ src/_Init.cpp | 2 +- 8 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 include/EventListener.h create mode 100644 include/EventManager.h create mode 100644 include/VEGO_Event.h create mode 100644 src/EventManager.cpp diff --git a/extern/SDL b/extern/SDL index e027b85..f686492 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit e027b85cc457556071cbb2f3f1bcf8803c1bc001 +Subproject commit f6864924f76e1a0b4abaefc76ae2ed22b1a8916e diff --git a/include/EventListener.h b/include/EventListener.h new file mode 100644 index 0000000..6e124ab --- /dev/null +++ b/include/EventListener.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +class EventListener { +public: + virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* event) = 0; + EventListener() {}; + virtual ~EventListener() {}; +}; \ No newline at end of file diff --git a/include/EventManager.h b/include/EventManager.h new file mode 100644 index 0000000..04daeb6 --- /dev/null +++ b/include/EventManager.h @@ -0,0 +1,18 @@ +#pragma once + +#include "EventListener.h" + +#include +#include +#include + +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" + +class EventManager { +public: + void registerListener(EventListener* listener, std::initializer_list eventTypes); + SDL_AppResult handleEvent(SDL_Event* event); +private: + std::map> eventListeners = std::map>(); +}; \ No newline at end of file diff --git a/include/GameInternal.h b/include/GameInternal.h index 3850b43..aedfff4 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -7,7 +7,10 @@ #include #include +#include "EventManager.h" #include "Manager.h" +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" #include "Vector2D.h" #include "Entity.h" #include "RenderManager.h" @@ -31,6 +34,7 @@ public: SDL_AppResult init(); void handleEvents(); + SDL_AppResult handleEvent(SDL_Event* event); void update(Uint64 frameTime); void render(); void clean(); @@ -47,6 +51,7 @@ public: Manager manager; RenderManager renderManager; + EventManager eventManager; Map* map; // game specific, might not be needed for all types of games ConfigLoader* config; diff --git a/include/VEGO_Event.h b/include/VEGO_Event.h new file mode 100644 index 0000000..b74e1a2 --- /dev/null +++ b/include/VEGO_Event.h @@ -0,0 +1,5 @@ +#pragma once + +enum VEGO_Event { + VEGO_Event_Interaction = SDL_EVENT_USER +}; \ No newline at end of file diff --git a/src/EventManager.cpp b/src/EventManager.cpp new file mode 100644 index 0000000..93e760b --- /dev/null +++ b/src/EventManager.cpp @@ -0,0 +1,33 @@ +#include "EventManager.h" +#include "EventListener.h" +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" +#include +#include +#include + +void EventManager::registerListener(EventListener* listener, std::initializer_list eventTypes) +{ + std::ranges::for_each(eventTypes.begin(), eventTypes.end(), [this, &listener](const SDL_EventType& eventType) { + if (!this->eventListeners.contains(eventType)) { + this->eventListeners.insert({eventType, std::vector()}); + } + this->eventListeners.at(eventType).emplace_back(listener); + }); +} + +SDL_AppResult EventManager::handleEvent(SDL_Event* event) +{ + SDL_EventType type = (SDL_EventType) event->type; + if (this->eventListeners.contains(type)) { + auto results = this->eventListeners.at(type) | std::views::transform( + [&event](EventListener* listener) { + return listener->handleEvent((SDL_EventType) event->type, event); + }); + if (std::ranges::contains(results, SDL_APP_FAILURE)) + return SDL_APP_FAILURE; + if (std::ranges::contains(results, SDL_APP_SUCCESS)) + return SDL_APP_SUCCESS; + } + return SDL_APP_CONTINUE; +} \ No newline at end of file diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 77becb6..8e8d605 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -4,6 +4,7 @@ #include "AssetManager.h" #include "RenderManager.h" #include +#include "SDL3/SDL_events.h" #include "SDL3/SDL_init.h" #include "SoundManager.h" #include "Entity.h" @@ -14,6 +15,7 @@ #include "GameFactory.h" #include +#include #include "ConfigLoader.h" @@ -44,6 +46,9 @@ SDL_AppResult GameInternal::init() GameInternal::soundManager = new SoundManager(); GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer? + /// \TODO: from c++26 you (should be able to) can loop through all values of an enum + SDL_RegisterEvents(VEGO_Event_Interaction); + int flags = 0; if (finalConfig.at("fullscreen")) { @@ -126,6 +131,10 @@ void GameInternal::handleEvents() } } +SDL_AppResult GameInternal::handleEvent(SDL_Event* event) { + return this->eventManager.handleEvent(event); +} + void GameInternal::update(Uint64 frameTime) { manager.refresh(); diff --git a/src/_Init.cpp b/src/_Init.cpp index d108b73..b32a1ea 100644 --- a/src/_Init.cpp +++ b/src/_Init.cpp @@ -40,7 +40,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) { } SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { - return SDL_APP_CONTINUE; + return vego::game->handleEvent(event); } void SDL_AppQuit(void *appstate, SDL_AppResult result) { From a9e754dd4fe6e6a7bfa225b43fdfc83345f14f3d Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Fri, 21 Mar 2025 17:19:50 +0100 Subject: [PATCH 39/42] Merge branch 'input2' into interactions-v2 --- include/EventListener.h | 2 +- include/EventManager.h | 2 +- include/GameInternal.h | 51 +++--- include/InputManager.h | 141 +++++++++++++++ src/GameInternal.cpp | 187 ++++++++++--------- src/InputManager.cpp | 384 ++++++++++++++++++++++++++++++++++++++++ src/_Init.cpp | 3 +- 7 files changed, 647 insertions(+), 123 deletions(-) create mode 100644 include/InputManager.h create mode 100644 src/InputManager.cpp diff --git a/include/EventListener.h b/include/EventListener.h index 6e124ab..5bdddc7 100644 --- a/include/EventListener.h +++ b/include/EventListener.h @@ -5,7 +5,7 @@ class EventListener { public: - virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* event) = 0; + virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) = 0; EventListener() {}; virtual ~EventListener() {}; }; \ No newline at end of file diff --git a/include/EventManager.h b/include/EventManager.h index 04daeb6..1e48b16 100644 --- a/include/EventManager.h +++ b/include/EventManager.h @@ -12,7 +12,7 @@ class EventManager { public: void registerListener(EventListener* listener, std::initializer_list eventTypes); - SDL_AppResult handleEvent(SDL_Event* event); + SDL_AppResult handleEvent(SDL_Event* const event); private: std::map> eventListeners = std::map>(); }; \ No newline at end of file diff --git a/include/GameInternal.h b/include/GameInternal.h index aedfff4..4dead69 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -13,6 +13,7 @@ #include "SDL3/SDL_init.h" #include "Vector2D.h" #include "Entity.h" +#include "InputManager.h" #include "RenderManager.h" #include "ConfigLoader.h" @@ -28,50 +29,50 @@ class Game; class GameInternal { public: - GameInternal(); - ~GameInternal(); + GameInternal(); + ~GameInternal(); - SDL_AppResult init(); + SDL_AppResult init(); - void handleEvents(); SDL_AppResult handleEvent(SDL_Event* event); - void update(Uint64 frameTime); - void render(); - void clean(); - bool isRunning() const; - void setRunning(bool running); // TODO: should be private/not accesible for game dev - void stopGame(); + void update(Uint64 frameTime); + void render(); + void clean(); + bool isRunning() const; + void setRunning(bool running); // TODO: should be private/not accesible for game dev + void stopGame(); - /* static */ SDL_Renderer* renderer = nullptr; - /* static */ SDL_Event event; - /* static */ CollisionHandler* collisionHandler; + /* static */ SDL_Renderer* renderer = nullptr; + /* static */ SDL_Event event; + /* static */ CollisionHandler* collisionHandler; /* static */ AssetManager* assets; /* static */ TextureManager* textureManager; /* static */ SoundManager* soundManager; + /* static */ InputManager* inputManager; Manager manager; RenderManager renderManager; EventManager eventManager; Map* map; // game specific, might not be needed for all types of games - ConfigLoader* config; + ConfigLoader* config; - std::vector& tiles; - std::vector& players; - std::vector& projectiles; - std::vector& hearts; - std::vector& powerups; - // end moved globals + std::vector& tiles; + std::vector& players; + std::vector& projectiles; + std::vector& hearts; + std::vector& powerups; + // end moved globals void refreshPlayers(); private: - Game* gameInstance; + Game* gameInstance; - int counter = 0; - bool running = true; - SDL_Window* window; + int counter = 0; + bool running = true; + SDL_Window* window; - Uint64 lastFrameTime = 0; + Uint64 lastFrameTime = 0; }; diff --git a/include/InputManager.h b/include/InputManager.h new file mode 100644 index 0000000..b1f10e9 --- /dev/null +++ b/include/InputManager.h @@ -0,0 +1,141 @@ +#pragma once + +#include "EventListener.h" +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" +#include +#include +#include +#include +#include +#include + +class InputManager : public EventListener { +public: + enum class EventType { + KeyDown, + KeyUp + }; + + enum class Key + { + UP, + DOWN, + LEFT, + RIGHT, + SPACE, + ENTER, + ESCAPE, + TAB, + BACKSPACE, + DELETE, + HOME, + END, + PAGE_UP, + PAGE_DOWN, + INSERT, + CAPS_LOCK, + LEFT_SHIFT, + RIGHT_SHIFT, + LEFT_CTRL, + RIGHT_CTRL, + LEFT_ALT, + RIGHT_ALT, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + A, + B, + C, + D, + E, + F, + G, + H, + I, + J, + K, + L, + M, + N, + O, + P, + Q, + R, + S, + T, + U, + V, + W, + X, + Y, + Z, + NUM_0, + NUM_1, + NUM_2, + NUM_3, + NUM_4, + NUM_5, + NUM_6, + NUM_7, + NUM_8, + NUM_9, + LEFT_BRACKET, + RIGHT_BRACKET, + SEMICOLON, + APOSTROPHE, + COMMA, + PERIOD, + SLASH, + BACKSLASH, + GRAVE + }; + + struct InputAction { + std::string name; + std::vector bindings; + std::function callback; + }; + + InputManager(); + ~InputManager(); + + void init(); // see if necessary + void processEvents(); + void registerAction(const std::string& actionName, const std::vector& keys, std::function callback, const std::string& context); + + void setActiveContext(const std::string& context); + std::string getActiveContext() const; + + void rebindAction(const std::string& actionName, const std::vector& newBindings, const std::string& context); + void removeBindings(const std::string& actionName, const std::string& context); + std::vector getBindings(const std::string& actionName, const std::string& context) const; + std::vector getActionsByKey(const Key key) const; + +private: + // TODO: flesh this out to avoid loops in process actions + // additionally to actionsByContext, not instead + std::map> actionsByContext; + std::map> actionsByKey; + + std::map keyMap; + std::string activeContext; + + void initKeyMap(); + SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) override; +}; + +std::ostream& operator<<(std::ostream& os, InputManager::Key key); +std::ostream& operator<<(std::ostream& os, const InputManager::InputAction& action); +std::ostream& operator<<(std::ostream& os, const InputManager::InputAction* action); +std::ostream& operator<<(std::ostream& os, const std::vector& actions); +std::ostream& operator<<(std::ostream& os, const std::vector& actions); diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 8e8d605..e57c4c7 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -6,6 +6,7 @@ #include #include "SDL3/SDL_events.h" #include "SDL3/SDL_init.h" +#include "SDL3/SDL_oldnames.h" #include "SoundManager.h" #include "Entity.h" #include "HealthComponent.h" @@ -20,161 +21,157 @@ #include "ConfigLoader.h" GameInternal::GameInternal() : - manager(this), - renderManager(), - tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)), - players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)), - projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)), - hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)), - powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS)) + manager(this), + renderManager(), + tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)), + players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)), + projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)), + hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)), + powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS)) {}; GameInternal::~GameInternal() = default; SDL_AppResult GameInternal::init() { - config = new ConfigLoader(); + config = new ConfigLoader(); - this->gameInstance = GameFactory::instance().create(this); - config->setCustomConfig(this->gameInstance->setConfigFilePath()); - config->init(); + this->gameInstance = GameFactory::instance().create(this); + config->setCustomConfig(this->gameInstance->setConfigFilePath()); + config->init(); - json finalConfig = config->getFinalConfig(); + 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? + GameInternal::inputManager = new InputManager(); + + this->eventManager.registerListener(inputManager, { SDL_EVENT_KEY_DOWN, SDL_EVENT_KEY_UP }); - 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? - /// \TODO: from c++26 you (should be able to) can loop through all values of an enum SDL_RegisterEvents(VEGO_Event_Interaction); - int flags = 0; - if (finalConfig.at("fullscreen")) - { - flags = SDL_WINDOW_FULLSCREEN; - } + int flags = 0; + if (finalConfig.at("fullscreen")) + { + flags = SDL_WINDOW_FULLSCREEN; + } - if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) - { - std::cout << "ERROR. Subsystem couldnt be initialized! " << SDL_GetError() << std::endl; - SDL_ClearError(); - return SDL_APP_FAILURE; - } + if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) + { + std::cout << "ERROR. Subsystem couldnt be initialized! " << SDL_GetError() << std::endl; + SDL_ClearError(); + return SDL_APP_FAILURE; + } - if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { - std::cout << "ERROR. Subsystem couldnt be initialized!" << std::endl; - return SDL_APP_FAILURE; - } + if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { + std::cout << "ERROR. Subsystem couldnt be initialized!" << std::endl; + return SDL_APP_FAILURE; + } - window = SDL_CreateWindow(finalConfig.at("title").get().c_str(), - finalConfig.at("screen_width"), finalConfig.at("screen_height"), flags); + window = SDL_CreateWindow(finalConfig.at("title").get().c_str(), + finalConfig.at("screen_width"), finalConfig.at("screen_height"), flags); - if (!window) - { - std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; - SDL_ClearError(); - return SDL_APP_FAILURE; - } + if (!window) + { + std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; + SDL_ClearError(); + return SDL_APP_FAILURE; + } // bad SDL_Surface* icon; if((icon = SDL_LoadBMP(finalConfig.at("icon").get().c_str()))) { - SDL_SetWindowIcon(window, icon); + SDL_SetWindowIcon(window, icon); } SDL_SetWindowIcon(window, icon); - renderer = SDL_CreateRenderer(window, NULL); - if (!renderer) - { - std::cout << "ERROR: Renderer couldnt be created! " << SDL_GetError() << std::endl; - SDL_ClearError(); - return SDL_APP_FAILURE; - } - SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + renderer = SDL_CreateRenderer(window, NULL); + if (!renderer) + { + std::cout << "ERROR: Renderer couldnt be created! " << SDL_GetError() << std::endl; + SDL_ClearError(); + return SDL_APP_FAILURE; + } + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - if (!Mix_OpenAudio(0, NULL)) - { - std::cout << "ERROR: Mixer couldnt be initialized! " << SDL_GetError() << std::endl; - SDL_ClearError(); - return SDL_APP_FAILURE; - } + if (!Mix_OpenAudio(0, NULL)) + { + std::cout << "ERROR: Mixer couldnt be initialized! " << SDL_GetError() << std::endl; + SDL_ClearError(); + return SDL_APP_FAILURE; + } - Mix_Volume(-1, MIX_MAX_VOLUME); - Mix_AllocateChannels(16); + Mix_Volume(-1, MIX_MAX_VOLUME); + Mix_AllocateChannels(16); - // loading sounds - // assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav"); - // assets->addSoundEffect("steps", "assets/sound/steps.wav"); + // loading sounds + // assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav"); + // assets->addSoundEffect("steps", "assets/sound/steps.wav"); - // loading music - // assets->addMusic("background_music", "assets/sound/background_music.mp3"); + // loading music + // assets->addMusic("background_music", "assets/sound/background_music.mp3"); - this->gameInstance->init(); + this->gameInstance->init(); - return SDL_APP_CONTINUE; -} - -void GameInternal::handleEvents() -{ - SDL_PollEvent(&event); - - switch (event.type) - { - case SDL_EVENT_QUIT: this->setRunning(false); - break; - - default: - break; - } + return SDL_APP_CONTINUE; } SDL_AppResult GameInternal::handleEvent(SDL_Event* event) { - return this->eventManager.handleEvent(event); + SDL_AppResult result = this->eventManager.handleEvent(event); + + if (event->type == SDL_EVENT_QUIT) { + this->clean(); + return result == SDL_APP_FAILURE ? SDL_APP_FAILURE : SDL_APP_SUCCESS; + } + + return result; } void GameInternal::update(Uint64 frameTime) { - manager.refresh(); + manager.refresh(); - uint_fast16_t diffTime = frameTime - this->lastFrameTime; - manager.update(diffTime); + uint_fast16_t diffTime = frameTime - this->lastFrameTime; + manager.update(diffTime); - this->gameInstance->update(diffTime); // TODO: this might have to be split up into two update functions, before and after manager... + this->gameInstance->update(diffTime); // TODO: this might have to be split up into two update functions, before and after manager... - this->lastFrameTime = frameTime; + this->lastFrameTime = frameTime; } void GameInternal::render() { - SDL_RenderClear(renderer); - this->renderManager.renderAll(); - SDL_RenderPresent(renderer); + SDL_RenderClear(renderer); + this->renderManager.renderAll(); + SDL_RenderPresent(renderer); } void GameInternal::clean() { - delete(textureManager); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - std::cout << "Game Cleaned!" << std::endl; + delete(textureManager); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + std::cout << "Game Cleaned!" << std::endl; } bool GameInternal::isRunning() const { - return running; + return running; } void GameInternal::setRunning(bool running) //TODO: might be depracted { - this->running = running; + this->running = running; } void GameInternal::stopGame() { - this->running = false; + this->running = false; } diff --git a/src/InputManager.cpp b/src/InputManager.cpp new file mode 100644 index 0000000..bb57541 --- /dev/null +++ b/src/InputManager.cpp @@ -0,0 +1,384 @@ +#include "InputManager.h" +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" +#include + +std::ostream& operator<<(std::ostream& os, InputManager::Key key) { + static const std::unordered_map keyToString { + {InputManager::Key::UP, "UP"}, + {InputManager::Key::DOWN, "DOWN"}, + {InputManager::Key::LEFT, "LEFT"}, + {InputManager::Key::RIGHT, "RIGHT"}, + {InputManager::Key::SPACE, "SPACE"}, + {InputManager::Key::ENTER, "ENTER"}, + {InputManager::Key::ESCAPE, "ESCAPE"}, + {InputManager::Key::TAB, "TAB"}, + {InputManager::Key::BACKSPACE, "BACKSPACE"}, + {InputManager::Key::DELETE, "DELETE"}, + {InputManager::Key::HOME, "HOME"}, + {InputManager::Key::END, "END"}, + {InputManager::Key::PAGE_UP, "PAGE_UP"}, + {InputManager::Key::PAGE_DOWN, "PAGE_DOWN"}, + {InputManager::Key::INSERT, "INSERT"}, + {InputManager::Key::CAPS_LOCK, "CAPS_LOCK"}, + {InputManager::Key::LEFT_SHIFT, "LEFT_SHIFT"}, + {InputManager::Key::RIGHT_SHIFT, "RIGHT_SHIFT"}, + {InputManager::Key::LEFT_CTRL, "LEFT_CTRL"}, + {InputManager::Key::RIGHT_CTRL, "RIGHT_CTRL"}, + {InputManager::Key::LEFT_ALT, "LEFT_ALT"}, + {InputManager::Key::RIGHT_ALT, "RIGHT_ALT"}, + {InputManager::Key::F1, "F1"}, + {InputManager::Key::F2, "F2"}, + {InputManager::Key::F3, "F3"}, + {InputManager::Key::F4, "F4"}, + {InputManager::Key::F5, "F5"}, + {InputManager::Key::F6, "F6"}, + {InputManager::Key::F7, "F7"}, + {InputManager::Key::F8, "F8"}, + {InputManager::Key::F9, "F9"}, + {InputManager::Key::F10, "F10"}, + {InputManager::Key::F11, "F11"}, + {InputManager::Key::F12, "F12"}, + {InputManager::Key::A, "A"}, + {InputManager::Key::B, "B"}, + {InputManager::Key::C, "C"}, + {InputManager::Key::D, "D"}, + {InputManager::Key::E, "E"}, + {InputManager::Key::F, "F"}, + {InputManager::Key::G, "G"}, + {InputManager::Key::H, "H"}, + {InputManager::Key::I, "I"}, + {InputManager::Key::J, "J"}, + {InputManager::Key::K, "K"}, + {InputManager::Key::L, "L"}, + {InputManager::Key::M, "M"}, + {InputManager::Key::N, "N"}, + {InputManager::Key::O, "O"}, + {InputManager::Key::P, "P"}, + {InputManager::Key::Q, "Q"}, + {InputManager::Key::R, "R"}, + {InputManager::Key::S, "S"}, + {InputManager::Key::T, "T"}, + {InputManager::Key::U, "U"}, + {InputManager::Key::V, "V"}, + {InputManager::Key::W, "W"}, + {InputManager::Key::X, "X"}, + {InputManager::Key::Y, "Y"}, + {InputManager::Key::Z, "Z"}, + {InputManager::Key::NUM_0, "NUM_0"}, + {InputManager::Key::NUM_1, "NUM_1"}, + {InputManager::Key::NUM_2, "NUM_2"}, + {InputManager::Key::NUM_3, "NUM_3"}, + {InputManager::Key::NUM_4, "NUM_4"}, + {InputManager::Key::NUM_5, "NUM_5"}, + {InputManager::Key::NUM_6, "NUM_6"}, + {InputManager::Key::NUM_7, "NUM_7"}, + {InputManager::Key::NUM_8, "NUM_8"}, + {InputManager::Key::NUM_9, "NUM_9"}, + {InputManager::Key::LEFT_BRACKET, "LEFT_BRACKET"}, + {InputManager::Key::RIGHT_BRACKET, "RIGHT_BRACKET"}, + {InputManager::Key::SEMICOLON, "SEMICOLON"}, + {InputManager::Key::APOSTROPHE, "APOSTROPHE"}, + {InputManager::Key::COMMA, "COMMA"}, + {InputManager::Key::PERIOD, "PERIOD"}, + {InputManager::Key::SLASH, "SLASH"}, + {InputManager::Key::BACKSLASH, "BACKSLASH"}, + {InputManager::Key::GRAVE, "GRAVE"} + }; + + auto it = keyToString.find(key); + if (it != keyToString.end()) { + os << it->second; + } else { + os << "UNKNOWN_KEY"; + } + return os; +} + +std::ostream& operator<<(std::ostream& os, const InputManager::InputAction& action) { + os << action.name << " with binding(s): "; + for (size_t i = 0; i < action.bindings.size(); ++i) { + os << action.bindings[i]; + + if (i < action.bindings.size() - 1) { + os << ", "; + } + } + return os; +} + +std::ostream& operator<<(std::ostream& os, const InputManager::InputAction* action) { + if (action) { + os << *action; + } else { + os << "NULL_ACTION"; + } + return os; +} + +std::ostream& operator<<(std::ostream& os, const std::vector& actions) { + os << "Actions: "; + if (actions.empty()) { + os << "None"; + } else { + for (size_t i = 0; i < actions.size(); ++i) { + os << actions[i]; + if (i < actions.size() - 1) { + os << " | "; + } + } + } + return os; +} + +// TODO: find out why it doesnt work?? +std::ostream& operator<<(std::ostream& os, const std::vector& actions) { + os << "Actions: "; + if (actions.empty()) { + os << "None"; + } else { + for (size_t i = 0; i < actions.size(); ++i) { + if (actions[i]) { + os << *actions[i]; + } else { + os << "NULL_ACTION"; + } + if (i < actions.size() - 1) { + os << " | "; + } + } + } + return os; +} + + + + +// overloads end -------------------------------------------------------------------------------------- + + + + + +InputManager::InputManager() : activeContext("Default") {} + +InputManager::~InputManager() {} + +void InputManager::init() { + if (SDL_Init(SDL_INIT_EVENTS) != 0) { + std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl; + return; + } +} + +void InputManager::initKeyMap() { + keyMap = { + {Key::UP, SDL_SCANCODE_UP}, + {Key::DOWN, SDL_SCANCODE_DOWN}, + {Key::LEFT, SDL_SCANCODE_LEFT}, + {Key::RIGHT, SDL_SCANCODE_RIGHT}, + {Key::SPACE, SDL_SCANCODE_SPACE}, + {Key::ENTER, SDL_SCANCODE_RETURN}, + {Key::ESCAPE, SDL_SCANCODE_ESCAPE}, + {Key::TAB, SDL_SCANCODE_TAB}, + {Key::BACKSPACE, SDL_SCANCODE_BACKSPACE}, + {Key::DELETE, SDL_SCANCODE_DELETE}, + {Key::HOME, SDL_SCANCODE_HOME}, + {Key::END, SDL_SCANCODE_END}, + {Key::PAGE_UP, SDL_SCANCODE_PAGEUP}, + {Key::PAGE_DOWN, SDL_SCANCODE_PAGEDOWN}, + {Key::INSERT, SDL_SCANCODE_INSERT}, + {Key::CAPS_LOCK, SDL_SCANCODE_CAPSLOCK}, + {Key::LEFT_SHIFT, SDL_SCANCODE_LSHIFT}, + {Key::RIGHT_SHIFT, SDL_SCANCODE_RSHIFT}, + {Key::LEFT_CTRL, SDL_SCANCODE_LCTRL}, + {Key::RIGHT_CTRL, SDL_SCANCODE_RCTRL}, + {Key::LEFT_ALT, SDL_SCANCODE_LALT}, + {Key::RIGHT_ALT, SDL_SCANCODE_RALT}, + {Key::F1, SDL_SCANCODE_F1}, + {Key::F2, SDL_SCANCODE_F2}, + {Key::F3, SDL_SCANCODE_F3}, + {Key::F4, SDL_SCANCODE_F4}, + {Key::F5, SDL_SCANCODE_F5}, + {Key::F6, SDL_SCANCODE_F6}, + {Key::F7, SDL_SCANCODE_F7}, + {Key::F8, SDL_SCANCODE_F8}, + {Key::F9, SDL_SCANCODE_F9}, + {Key::F10, SDL_SCANCODE_F10}, + {Key::F11, SDL_SCANCODE_F11}, + {Key::F12, SDL_SCANCODE_F12}, + {Key::A, SDL_SCANCODE_A}, + {Key::B, SDL_SCANCODE_B}, + {Key::C, SDL_SCANCODE_C}, + {Key::D, SDL_SCANCODE_D}, + {Key::E, SDL_SCANCODE_E}, + {Key::F, SDL_SCANCODE_F}, + {Key::G, SDL_SCANCODE_G}, + {Key::H, SDL_SCANCODE_H}, + {Key::I, SDL_SCANCODE_I}, + {Key::J, SDL_SCANCODE_J}, + {Key::K, SDL_SCANCODE_K}, + {Key::L, SDL_SCANCODE_L}, + {Key::M, SDL_SCANCODE_M}, + {Key::N, SDL_SCANCODE_N}, + {Key::O, SDL_SCANCODE_O}, + {Key::P, SDL_SCANCODE_P}, + {Key::Q, SDL_SCANCODE_Q}, + {Key::R, SDL_SCANCODE_R}, + {Key::S, SDL_SCANCODE_S}, + {Key::T, SDL_SCANCODE_T}, + {Key::U, SDL_SCANCODE_U}, + {Key::V, SDL_SCANCODE_V}, + {Key::W, SDL_SCANCODE_W}, + {Key::X, SDL_SCANCODE_X}, + {Key::Y, SDL_SCANCODE_Y}, + {Key::Z, SDL_SCANCODE_Z}, + {Key::NUM_0, SDL_SCANCODE_0}, + {Key::NUM_1, SDL_SCANCODE_1}, + {Key::NUM_2, SDL_SCANCODE_2}, + {Key::NUM_3, SDL_SCANCODE_3}, + {Key::NUM_4, SDL_SCANCODE_4}, + {Key::NUM_5, SDL_SCANCODE_5}, + {Key::NUM_6, SDL_SCANCODE_6}, + {Key::NUM_7, SDL_SCANCODE_7}, + {Key::NUM_8, SDL_SCANCODE_8}, + {Key::NUM_9, SDL_SCANCODE_9}, + {Key::LEFT_BRACKET, SDL_SCANCODE_LEFTBRACKET}, + {Key::RIGHT_BRACKET, SDL_SCANCODE_RIGHTBRACKET}, + {Key::SEMICOLON, SDL_SCANCODE_SEMICOLON}, + {Key::APOSTROPHE, SDL_SCANCODE_APOSTROPHE}, + {Key::COMMA, SDL_SCANCODE_COMMA}, + {Key::PERIOD, SDL_SCANCODE_PERIOD}, + {Key::SLASH, SDL_SCANCODE_SLASH}, + {Key::BACKSLASH, SDL_SCANCODE_BACKSLASH}, + {Key::GRAVE, SDL_SCANCODE_GRAVE} + }; +} + +void InputManager::registerAction(const std::string& actionName, const std::vector& keys, std::function callback, const std::string& context) { + actionsByContext[context].emplace_back(actionName, keys, callback); + InputAction& storedAction = actionsByContext[context].back(); + for (const auto& key : keys) { + actionsByKey[key].push_back(&storedAction); + } + std::cout << "Registered action: " << storedAction << " in context: " << context << std::endl; +} + +void InputManager::rebindAction(const std::string& actionName, const std::vector& newBindings, const std::string& context) { + auto it = actionsByContext.find(context); + if (it != actionsByContext.end()) { + for (auto& action : it->second) { + if (action.name == actionName) { + for (const auto& key : action.bindings) { + auto& keyActions = actionsByKey[key]; + keyActions.erase(std::remove(keyActions.begin(), keyActions.end(), &action), keyActions.end()); + if (keyActions.empty()) { + actionsByKey.erase(key); + } + } + + action.bindings = newBindings; + + for (const auto& key : newBindings) { + actionsByKey[key].push_back(&action); + } + + std::cout << "Rebound action: " << actionName << " in context: " << context << " to new bindings: "; + for (const auto& key : newBindings) { + std::cout << key << " "; + } + std::cout << std::endl; + return; + } + } + } + std::cout << "Action not found: " << actionName << " in context: " << context << std::endl; +} + +void InputManager::removeBindings(const std::string& actionName, const std::string& context) { + auto it = actionsByContext.find(context); + if (it != actionsByContext.end()) { + for (auto& action : it->second) { + if (action.name == actionName) { + action.bindings.clear(); + std::cout << "Removed bindings for action: " << actionName << " in context: " << context << std::endl; + return; + } + } + } + std::cout << "Action not found: " << actionName << " in context: " << context << std::endl; +} + +std::vector InputManager::getBindings(const std::string& actionName, const std::string& context) const { + auto it = actionsByContext.find(context); + if (it != actionsByContext.end()) { + for (const auto& action : it->second) { + if (action.name == actionName) { + return action.bindings; + } + } + } + std::cout << "Action not found: " << actionName << " in context: " << context << "\n"; + return {}; +} + +std::vector InputManager::getActionsByKey(const Key key) const { + auto it = actionsByKey.find(key); + if (it != actionsByKey.end()) { + std::cout << "DEBUG: Found " << it->second.size() << " actions for key " << key << std::endl; + return it->second; + } + std::cout << "DEBUG: No actions found for key " << key << std::endl; + return {}; +} + +void InputManager::setActiveContext(const std::string& context) { + activeContext = context; + std::cout << "Active context set to: " << activeContext << std::endl; +} + +std::string InputManager::getActiveContext() const { + return activeContext; +} + +SDL_AppResult InputManager::handleEvent(SDL_EventType type, SDL_Event* const event) { + std::cout << "in handleEvent" << std::endl; + if (type != SDL_EVENT_KEY_DOWN) { + std::cout << "ignore key up" << std::endl; + return SDL_APP_CONTINUE; + } + + if (event->key.repeat) { + std::cout << "ignore key repeat" << std::endl; + return SDL_APP_CONTINUE; + } + + auto keyIt = std::ranges::find_if(keyMap, + [&](const auto& pair) { return pair.second == event->key.scancode; }); + + if (keyIt != keyMap.end()) { + std::cout << "in != keymap.end" << std::endl; + + Key pressedKey = keyIt->first; + auto actionIt = actionsByKey.find(pressedKey); + if (actionIt != actionsByKey.end()) { + std::cout << "in != actionsByKey.end" << std::endl; + + for (auto* action : actionIt->second) { + std::cout << "before if(action)" << std::endl; + if (action) { + std::cout << "after if(action)" << std::endl; + + auto& activeActions = actionsByContext[activeContext]; + if (std::ranges::find_if(activeActions, + [&](const InputAction& act) { return &act == action; }) != activeActions.end()) { + std::cout << "Action triggered: " << action->name << " in context: " << activeContext << std::endl; + action->callback(); + } + } + } + } + } + + return SDL_APP_CONTINUE; +} \ No newline at end of file diff --git a/src/_Init.cpp b/src/_Init.cpp index b32a1ea..1ea2523 100644 --- a/src/_Init.cpp +++ b/src/_Init.cpp @@ -27,7 +27,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) { return SDL_APP_SUCCESS; } - vego::game->handleEvents(); // bad + //vego::game->handleEvents(); // bad Uint64 frameStart = SDL_GetTicks(); @@ -39,6 +39,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) { return SDL_APP_CONTINUE; } +// triggers upon every event SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { return vego::game->handleEvent(event); } From 325f6e8e8d23ef79c0bb6f779c934bffafc2b19a Mon Sep 17 00:00:00 2001 From: Nimac0 Date: Sat, 22 Mar 2025 12:45:28 +0100 Subject: [PATCH 40/42] ref: powerup component now pickup component, assetmanager removed assetmanager was redundant therefore any traces and usages were removed --- include/GameInternal.h | 4 ++-- .../{PowerupComponent.h => PickupComponent.h} | 6 +++--- include/{AssetManager.h => PickupManager.h} | 15 +++----------- src/GameInternal.cpp | 5 ++--- ...werupComponent.cpp => PickupComponent.cpp} | 6 +++--- src/{AssetManager.cpp => PickupManager.cpp} | 20 +++++++------------ src/SoundManager.cpp | 1 - 7 files changed, 20 insertions(+), 37 deletions(-) rename include/{PowerupComponent.h => PickupComponent.h} (71%) rename include/{AssetManager.h => PickupManager.h} (67%) rename src/{PowerupComponent.cpp => PickupComponent.cpp} (76%) rename src/{AssetManager.cpp => PickupManager.cpp} (76%) diff --git a/include/GameInternal.h b/include/GameInternal.h index 3850b43..2f99092 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -12,10 +12,10 @@ #include "Entity.h" #include "RenderManager.h" #include "ConfigLoader.h" +#include "PickupManager.h" typedef std::function gamefunction; -class AssetManager; class CollisionHandler; class TextureManager; class SoundManager; @@ -41,7 +41,7 @@ public: /* static */ SDL_Renderer* renderer = nullptr; /* static */ SDL_Event event; /* static */ CollisionHandler* collisionHandler; - /* static */ AssetManager* assets; + /* static */ PickupManager* pickupManager; /* static */ TextureManager* textureManager; /* static */ SoundManager* soundManager; diff --git a/include/PowerupComponent.h b/include/PickupComponent.h similarity index 71% rename from include/PowerupComponent.h rename to include/PickupComponent.h index 7229283..bab061d 100644 --- a/include/PowerupComponent.h +++ b/include/PickupComponent.h @@ -3,15 +3,15 @@ #include #include "Component.h" -class PowerupComponent : public Component +class PickupComponent : public Component { public: /** * @brief Construct a new Powerup Component object * @param func The function to be called when the powerup is picked up */ - PowerupComponent(std::function func); - ~PowerupComponent() {}; + PickupComponent(std::function func); + ~PickupComponent() {}; void update(uint_fast16_t diffTime) override; diff --git a/include/AssetManager.h b/include/PickupManager.h similarity index 67% rename from include/AssetManager.h rename to include/PickupManager.h index 402e6b9..c73af76 100644 --- a/include/AssetManager.h +++ b/include/PickupManager.h @@ -11,25 +11,16 @@ class Vector2D; class Manager; -enum class PowerupType -{ - HEART, - WALKINGSPEED, - SHOOTINGSPEED -}; - -class AssetManager +class PickupManager { public: - AssetManager(Manager* manager); - ~AssetManager(); + PickupManager(Manager* manager); + ~PickupManager(); void createPowerup(Vector2D pos, std::function pickupFunc, Textures texture); Vector2D calculateSpawnPosition(); - PowerupType calculateType(); - private: diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index 77becb6..992abeb 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -1,7 +1,6 @@ #include "GameInternal.h" #include "CollisionHandler.h" -#include "AssetManager.h" #include "RenderManager.h" #include #include "SDL3/SDL_init.h" @@ -39,10 +38,10 @@ SDL_AppResult GameInternal::init() json finalConfig = config->getFinalConfig(); - GameInternal::assets = new AssetManager(&manager); + GameInternal::pickupManager = new PickupManager(&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? + GameInternal::collisionHandler = new CollisionHandler(manager); //why no pointer? int flags = 0; if (finalConfig.at("fullscreen")) diff --git a/src/PowerupComponent.cpp b/src/PickupComponent.cpp similarity index 76% rename from src/PowerupComponent.cpp rename to src/PickupComponent.cpp index 4db3f95..0c6a452 100644 --- a/src/PowerupComponent.cpp +++ b/src/PickupComponent.cpp @@ -1,4 +1,4 @@ -#include "PowerupComponent.h" +#include "PickupComponent.h" #include "GameInternal.h" #include "CollisionHandler.h" #include "Entity.h" @@ -7,12 +7,12 @@ #include "Constants.h" #include -PowerupComponent::PowerupComponent(std::function func) +PickupComponent::PickupComponent(std::function func) { this->pickupFunc = func; } -void PowerupComponent::update(uint_fast16_t diffTime) +void PickupComponent::update(uint_fast16_t diffTime) { Entity* player; if ((player = this->entity->getManager().getGame()->collisionHandler->getAnyIntersection( diff --git a/src/AssetManager.cpp b/src/PickupManager.cpp similarity index 76% rename from src/AssetManager.cpp rename to src/PickupManager.cpp index c4ae91d..21fe1ff 100644 --- a/src/AssetManager.cpp +++ b/src/PickupManager.cpp @@ -1,4 +1,4 @@ -#include "AssetManager.h" +#include "PickupManager.h" #include "TextureManager.h" #include "SoundManager.h" @@ -12,17 +12,17 @@ #include "Constants.h" #include "Entity.h" #include "Vector2D.h" -#include "PowerupComponent.h" +#include "PickupComponent.h" #include #include #include "Textures.h" -AssetManager::AssetManager(Manager* manager) : man(manager) {} +PickupManager::PickupManager(Manager* manager) : man(manager) {} -AssetManager::~AssetManager() {} +PickupManager::~PickupManager() {} -void AssetManager::createPowerup(Vector2D pos, std::function pickupFunc, Textures texture) { +void PickupManager::createPowerup(Vector2D pos, std::function pickupFunc, Textures texture) { auto& powerups(man->addEntity()); powerups.addComponent(pos.x, pos.y, 32, 32, 1); //32x32 is standard size for objects @@ -35,11 +35,11 @@ void AssetManager::createPowerup(Vector2D pos, std::function pic } powerups.addComponent("powerup", 0.6f); - powerups.addComponent(pickupFunc); + powerups.addComponent(pickupFunc); powerups.addGroup((size_t)Entity::GroupLabel::POWERUPS); } -Vector2D AssetManager::calculateSpawnPosition() +Vector2D PickupManager::calculateSpawnPosition() { Vector2D spawnPos = Vector2D(-1, -1); bool conflict = false; @@ -62,10 +62,4 @@ Vector2D AssetManager::calculateSpawnPosition() spawnPos = Vector2D(spawnRect.x, spawnRect.y); } return spawnPos; -} - -PowerupType AssetManager::calculateType() -{ - PowerupType type = PowerupType(rand() % 3); - return type; } \ No newline at end of file diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 80c5567..df683c2 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -6,7 +6,6 @@ #include #include "GameInternal.h" -#include "AssetManager.h" /* Mix_Music* SoundManager::loadMusic(const char* fileName) From adaed679af74e6f320bbefb5fdcf8fc8b6f2f0b9 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sat, 22 Mar 2025 14:38:26 +0100 Subject: [PATCH 41/42] InteractionManager + proof of concept --- include/Entity.h | 143 ++++++++++++++------------- include/EventListener.h | 11 --- include/EventManager.h | 11 ++- include/GameInternal.h | 6 +- include/InputManager.h | 10 +- include/InteractionEventdataStruct.h | 15 +++ include/InteractionListener.h | 17 ++++ include/InteractionManager.h | 35 +++++++ include/PowerupComponent.h | 23 +++-- include/RenderObject.h | 4 +- include/SpriteComponent.h | 5 + include/TextureManager.h | 6 ++ include/VEGO_Event.h | 8 +- src/AssetManager.cpp | 2 + src/Entity.cpp | 4 +- src/EventManager.cpp | 23 +++-- src/GameInternal.cpp | 17 ++-- src/InputManager.cpp | 7 +- src/InteractionManager.cpp | 90 +++++++++++++++++ src/PowerupComponent.cpp | 16 +++ src/RenderObject.cpp | 6 +- src/SpriteComponent.cpp | 2 +- src/TextureManager.cpp | 3 + 23 files changed, 339 insertions(+), 125 deletions(-) delete mode 100644 include/EventListener.h create mode 100644 include/InteractionEventdataStruct.h create mode 100644 include/InteractionListener.h create mode 100644 include/InteractionManager.h create mode 100644 src/InteractionManager.cpp diff --git a/include/Entity.h b/include/Entity.h index 5f8f3cc..978a9ac 100644 --- a/include/Entity.h +++ b/include/Entity.h @@ -35,85 +35,90 @@ class Entity { public: - /*! - * \brief Used for rendering order (last is highest) or retrieving entities of group - * \todo Label used in singular entity shouldn't use plural - * \todo HEARTS are rendered above POWERUPS, missleading order - * \todo PROJECTILE are rendered above POWERUPS, missleading order - * \todo Generalize HEARTS as UI or similar - */ - enum class GroupLabel - { - MAPTILES, //!< Entity using TileComponent - PLAYERS, //!< Primary entity in player controll - ENEMIES, //!< \deprecated All players now grouped as Entity::PLAYERS - COLLIDERS, //!< Fixed collider entity, e.g. a wall - PROJECTILE, //!< \todo Document - HEARTS, //!< \todo Document - POWERUPS //!< \todo Document - }; + /*! + * \brief Used for rendering order (last is highest) or retrieving entities of group + * \todo Label used in singular entity shouldn't use plural + * \todo HEARTS are rendered above POWERUPS, missleading order + * \todo PROJECTILE are rendered above POWERUPS, missleading order + * \todo Generalize HEARTS as UI or similar + */ + enum class GroupLabel + { + MAPTILES, //!< Entity using TileComponent + PLAYERS, //!< Primary entity in player controll + ENEMIES, //!< \deprecated All players now grouped as Entity::PLAYERS + COLLIDERS, //!< Fixed collider entity, e.g. a wall + PROJECTILE, //!< \todo Document + HEARTS, //!< \todo Document + POWERUPS //!< \todo Document + }; - /*! - * \todo Document - */ - explicit Entity(Manager& mManager) : - manager(mManager) { }; + /*! + * \todo Document + */ + explicit Entity(Manager& mManager) : + manager(mManager) { }; - void update(uint_fast16_t diffTime) const; //!< Call each frame to update all components + void update(uint_fast16_t diffTime) const; //!< Call each frame to update all components - bool isActive() const { return this->active; } //!< \sa destroy() - //! Mark for destruction for Manager::refresh() and disables collision - //! \sa ColliderComponent - void destroy() { - this->active = false; - if (this->hasComponent()) { - this->getComponent().removeCollision(); - } - } + bool isActive() const { return this->active; } //!< \sa destroy() + //! Mark for destruction for Manager::refresh() and disables collision + //! \sa ColliderComponent + void destroy() { + this->active = false; + if (this->hasComponent()) { + this->getComponent().removeCollision(); + } + } - bool hasGroup(Group mGroup); //!< \sa GroupLabel - void addGroup(Group mGroup); //!< \sa GroupLabel - void delGroup(Group mGroup); //!< \sa GroupLabel - //! \returns bitset with true on position GroupLabel if the entity belongs to group - //! \sa GroupLabel - std::bitset getGroupBitSet(); + bool hasGroup(Group mGroup); //!< \sa GroupLabel + void addGroup(Group mGroup); //!< \sa GroupLabel + void delGroup(Group mGroup); //!< \sa GroupLabel + //! \returns bitset with true on position GroupLabel if the entity belongs to group + //! \sa GroupLabel + std::bitset getGroupBitSet(); - //! \sa Manager - Manager& getManager() { return manager; }; + //! \sa Manager + Manager& getManager() { return manager; }; - template bool hasComponent() const //! \sa Component - { - return componentBitSet[getComponentTypeID()]; - } + template bool hasComponent() const //! \sa Component + { + return componentBitSet[getComponentTypeID()]; + } - //! \brief Adds specified type as component and calls Component::init() - //! \param mArgs Constructor arguments of component - template T& addComponent(TArgs&&...mArgs) - { - T* c(new T(std::forward(mArgs)...)); - c->entity = this; - std::unique_ptr uPtr{ c }; - this->components.emplace_back(std::move(uPtr)); + //! \brief Adds specified type as component and calls Component::init() + //! \param mArgs Constructor arguments of component + template T& addComponent(TArgs&&...mArgs) + { + T* c(new T(std::forward(mArgs)...)); + c->entity = this; + std::shared_ptr uPtr{ c }; + this->components.at(getComponentTypeID()) = std::move(uPtr); - componentArray[getComponentTypeID()] = c; - componentBitSet[getComponentTypeID()] = true; + componentArray[getComponentTypeID()] = c; + componentBitSet[getComponentTypeID()] = true; - c->init(); - return *c; - }; - - template T& getComponent() const //!< \todo: rewrite to use optionals - { - auto ptr(componentArray[getComponentTypeID()]); - return *static_cast(ptr); - } + c->init(); + return *c; + }; + + template T& getComponent() const //!< \todo: rewrite to use optionals + { + auto ptr(componentArray[getComponentTypeID()]); + return *static_cast(ptr); + } + + template std::shared_ptr getComponentAsPointer() const + { + return std::static_pointer_cast(components.at(getComponentTypeID())); + } private: - Manager& manager; - bool active = true; - std::vector> components; + Manager& manager; + bool active = true; + std::array, MAX_COMPONENTS> components; - ComponentArray componentArray = {}; - ComponentBitSet componentBitSet; - GroupBitSet groupBitSet; + ComponentArray componentArray = {}; + ComponentBitSet componentBitSet; + GroupBitSet groupBitSet; }; \ No newline at end of file diff --git a/include/EventListener.h b/include/EventListener.h deleted file mode 100644 index 5bdddc7..0000000 --- a/include/EventListener.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -class EventListener { -public: - virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) = 0; - EventListener() {}; - virtual ~EventListener() {}; -}; \ No newline at end of file diff --git a/include/EventManager.h b/include/EventManager.h index 1e48b16..3a4f0b4 100644 --- a/include/EventManager.h +++ b/include/EventManager.h @@ -1,7 +1,6 @@ #pragma once -#include "EventListener.h" - +#include #include #include #include @@ -9,10 +8,14 @@ #include "SDL3/SDL_events.h" #include "SDL3/SDL_init.h" +typedef std::function EventListener; + class EventManager { public: - void registerListener(EventListener* listener, std::initializer_list eventTypes); + EventManager(); + + void registerListener(EventListener listener, std::initializer_list eventTypes); SDL_AppResult handleEvent(SDL_Event* const event); private: - std::map> eventListeners = std::map>(); + std::map> eventListeners = std::map>(); }; \ No newline at end of file diff --git a/include/GameInternal.h b/include/GameInternal.h index 4dead69..8e046bb 100644 --- a/include/GameInternal.h +++ b/include/GameInternal.h @@ -8,6 +8,7 @@ #include #include "EventManager.h" +#include "InteractionManager.h" #include "Manager.h" #include "SDL3/SDL_events.h" #include "SDL3/SDL_init.h" @@ -49,10 +50,11 @@ public: /* static */ TextureManager* textureManager; /* static */ SoundManager* soundManager; /* static */ InputManager* inputManager; + RenderManager* renderManager; + EventManager* eventManager; + InteractionManager* interactionManager; Manager manager; - RenderManager renderManager; - EventManager eventManager; Map* map; // game specific, might not be needed for all types of games ConfigLoader* config; diff --git a/include/InputManager.h b/include/InputManager.h index b1f10e9..ebc6272 100644 --- a/include/InputManager.h +++ b/include/InputManager.h @@ -1,8 +1,7 @@ #pragma once -#include "EventListener.h" -#include "SDL3/SDL_events.h" -#include "SDL3/SDL_init.h" +#include +#include #include #include #include @@ -10,7 +9,7 @@ #include #include -class InputManager : public EventListener { +class InputManager { public: enum class EventType { KeyDown, @@ -121,6 +120,8 @@ public: std::vector getBindings(const std::string& actionName, const std::string& context) const; std::vector getActionsByKey(const Key key) const; + SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event); + private: // TODO: flesh this out to avoid loops in process actions // additionally to actionsByContext, not instead @@ -131,7 +132,6 @@ private: std::string activeContext; void initKeyMap(); - SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) override; }; std::ostream& operator<<(std::ostream& os, InputManager::Key key); diff --git a/include/InteractionEventdataStruct.h b/include/InteractionEventdataStruct.h new file mode 100644 index 0000000..036f03c --- /dev/null +++ b/include/InteractionEventdataStruct.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Entity.h" +#include "InteractionListener.h" +#include "Vector2D.h" +#include +#include + +struct InteractionEventdataStruct { + void* actor; // suggestion, can also be used for other arbitrary data + void* data; + std::weak_ptr target = std::weak_ptr(); + std::shared_ptr targetingReference; // required without explicit target + uint8_t strategy = 0; // required without explicit target, defaults to none +}; \ No newline at end of file diff --git a/include/InteractionListener.h b/include/InteractionListener.h new file mode 100644 index 0000000..06216db --- /dev/null +++ b/include/InteractionListener.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Vector2D.h" +#include + +class InteractionListener { +public: + InteractionListener() { }; + virtual ~InteractionListener() { }; + + virtual void interact(void* actor, void* data) = 0; + virtual std::shared_ptr getPosition() // required for targeting strategy, return null to only allow explicit targeting + { + return nullptr; + } + +}; \ No newline at end of file diff --git a/include/InteractionManager.h b/include/InteractionManager.h new file mode 100644 index 0000000..f465fcb --- /dev/null +++ b/include/InteractionManager.h @@ -0,0 +1,35 @@ +#pragma once + +#include "InteractionListener.h" + +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_init.h" +#include +#include +#include +#include +#include + +// TODO: ranges concept to avoid to in cpp +typedef std::function(Vector2D*, std::vector>)> TargetingFunc; + +class InteractionManager { +public: + InteractionManager(); + InteractionManager (const InteractionManager&) = delete; + InteractionManager& operator= (const InteractionManager&) = delete; + + enum class TargetingStrategy : uint8_t { + none = 0, + closest, + manhattenDistance + }; + + SDL_AppResult handleInteract(SDL_EventType type, SDL_Event* const event); + void registerListener(std::weak_ptr listener); + uint8_t registerTargetingFunc(TargetingFunc func); +private: + + std::vector> listeners; + std::array targetingFuncs; +}; \ No newline at end of file diff --git a/include/PowerupComponent.h b/include/PowerupComponent.h index 7229283..f7bef62 100644 --- a/include/PowerupComponent.h +++ b/include/PowerupComponent.h @@ -2,19 +2,24 @@ #include #include "Component.h" +#include "InteractionListener.h" -class PowerupComponent : public Component +class PowerupComponent : public Component, public InteractionListener { public: - /** - * @brief Construct a new Powerup Component object - * @param func The function to be called when the powerup is picked up - */ - PowerupComponent(std::function func); - ~PowerupComponent() {}; + /** + * @brief Construct a new Powerup Component object + * @param func The function to be called when the powerup is picked up + */ + PowerupComponent(std::function func); + ~PowerupComponent() {}; - void update(uint_fast16_t diffTime) override; + void update(uint_fast16_t diffTime) override; + + + void interact(void* actor, void* data) override; + std::shared_ptr getPosition() override; private: - std::function pickupFunc; + std::function pickupFunc; }; \ No newline at end of file diff --git a/include/RenderObject.h b/include/RenderObject.h index ba4b929..9b3e881 100644 --- a/include/RenderObject.h +++ b/include/RenderObject.h @@ -7,7 +7,7 @@ class RenderObject public: virtual void draw() = 0; - RenderObject(int zIndex, RenderManager& renderManager); + RenderObject(int zIndex, RenderManager* renderManager); ~RenderObject(); int getZIndex() { return this->zIndex; }; @@ -23,5 +23,5 @@ private: int zIndex = 0; protected: - RenderManager& renderManager; + RenderManager* renderManager; }; \ No newline at end of file diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 7a82487..247a063 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -40,6 +40,11 @@ private: const char* path; //!< empty string if texture has a texture enum value, otherwise the path of the texture public: + //debug + Textures getTexture() { return this->textureEnum; } + + + SpriteComponent(Textures texture, int zIndex); SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex); SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex); diff --git a/include/TextureManager.h b/include/TextureManager.h index 17f0903..a7f1e29 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -83,9 +83,15 @@ class TextureManager */ SDL_Texture* loadMapTileTexture(const char* path); + std::string getTexturePath(Textures texture) { + return this->texture_references.at(texture); + } + private: SDL_ScaleMode scaleMode = SDL_SCALEMODE_NEAREST; Manager* manager; std::map texture_cache; std::map mapTile_texture_cache; + + std::map texture_references; }; \ No newline at end of file diff --git a/include/VEGO_Event.h b/include/VEGO_Event.h index b74e1a2..a90d46a 100644 --- a/include/VEGO_Event.h +++ b/include/VEGO_Event.h @@ -1,5 +1,7 @@ #pragma once -enum VEGO_Event { - VEGO_Event_Interaction = SDL_EVENT_USER -}; \ No newline at end of file +#include + +namespace vego { + extern Uint32 VEGO_Event_Interaction; +} \ No newline at end of file diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index c4ae91d..ee589e0 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -37,6 +37,8 @@ void AssetManager::createPowerup(Vector2D pos, std::function pic powerups.addComponent("powerup", 0.6f); powerups.addComponent(pickupFunc); powerups.addGroup((size_t)Entity::GroupLabel::POWERUPS); + + VEGO_Game().interactionManager->registerListener(powerups.getComponentAsPointer()); } Vector2D AssetManager::calculateSpawnPosition() diff --git a/src/Entity.cpp b/src/Entity.cpp index 987626d..8a4a0e9 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -6,7 +6,9 @@ void Entity::update(uint_fast16_t diffTime) const { - for (auto const& c : components) c->update(diffTime); + for (auto const& c : components) + if (c) + c->update(diffTime); } bool Entity::hasGroup(Group mGroup) diff --git a/src/EventManager.cpp b/src/EventManager.cpp index 93e760b..049a8b0 100644 --- a/src/EventManager.cpp +++ b/src/EventManager.cpp @@ -1,16 +1,27 @@ #include "EventManager.h" -#include "EventListener.h" #include "SDL3/SDL_events.h" #include "SDL3/SDL_init.h" +#include "SDL3/SDL_stdinc.h" +#include "VEGO_Event.h" #include +#include #include #include -void EventManager::registerListener(EventListener* listener, std::initializer_list eventTypes) +Uint32 vego::VEGO_Event_Interaction; + +EventManager::EventManager() { - std::ranges::for_each(eventTypes.begin(), eventTypes.end(), [this, &listener](const SDL_EventType& eventType) { + + /// \TODO: from c++26 you (should be able to) can get the amount of name values in an enum + vego::VEGO_Event_Interaction = SDL_RegisterEvents(1); // TODO: error handling +} + +void EventManager::registerListener(EventListener listener, std::initializer_list eventTypes) +{ + std::ranges::for_each(eventTypes.begin(), eventTypes.end(), [this, &listener](const Uint32& eventType) { if (!this->eventListeners.contains(eventType)) { - this->eventListeners.insert({eventType, std::vector()}); + this->eventListeners.insert({eventType, std::vector()}); } this->eventListeners.at(eventType).emplace_back(listener); }); @@ -21,8 +32,8 @@ SDL_AppResult EventManager::handleEvent(SDL_Event* event) SDL_EventType type = (SDL_EventType) event->type; if (this->eventListeners.contains(type)) { auto results = this->eventListeners.at(type) | std::views::transform( - [&event](EventListener* listener) { - return listener->handleEvent((SDL_EventType) event->type, event); + [&event](EventListener listener) { + return listener((SDL_EventType) event->type, event); }); if (std::ranges::contains(results, SDL_APP_FAILURE)) return SDL_APP_FAILURE; diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index e57c4c7..d4aea1a 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -2,6 +2,9 @@ #include "CollisionHandler.h" #include "AssetManager.h" +#include "EventManager.h" +#include "InputManager.h" +#include "InteractionManager.h" #include "RenderManager.h" #include #include "SDL3/SDL_events.h" @@ -17,12 +20,12 @@ #include #include +#include #include "ConfigLoader.h" GameInternal::GameInternal() : manager(this), - renderManager(), tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)), players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)), projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)), @@ -48,10 +51,12 @@ SDL_AppResult GameInternal::init() GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer? GameInternal::inputManager = new InputManager(); - this->eventManager.registerListener(inputManager, { SDL_EVENT_KEY_DOWN, SDL_EVENT_KEY_UP }); + GameInternal::renderManager = new RenderManager(); + GameInternal::eventManager = new EventManager(); + GameInternal::interactionManager = new InteractionManager(); - /// \TODO: from c++26 you (should be able to) can loop through all values of an enum - SDL_RegisterEvents(VEGO_Event_Interaction); + this->eventManager->registerListener(std::bind_front(&InputManager::handleEvent, this->inputManager), { SDL_EVENT_KEY_DOWN, SDL_EVENT_KEY_UP }); + this->eventManager->registerListener(std::bind_front(&InteractionManager::handleInteract, VEGO_Game().interactionManager), { vego::VEGO_Event_Interaction }); int flags = 0; if (finalConfig.at("fullscreen")) @@ -122,7 +127,7 @@ SDL_AppResult GameInternal::init() } SDL_AppResult GameInternal::handleEvent(SDL_Event* event) { - SDL_AppResult result = this->eventManager.handleEvent(event); + SDL_AppResult result = this->eventManager->handleEvent(event); if (event->type == SDL_EVENT_QUIT) { this->clean(); @@ -147,7 +152,7 @@ void GameInternal::update(Uint64 frameTime) void GameInternal::render() { SDL_RenderClear(renderer); - this->renderManager.renderAll(); + this->renderManager->renderAll(); SDL_RenderPresent(renderer); } diff --git a/src/InputManager.cpp b/src/InputManager.cpp index bb57541..6542ec3 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -1,7 +1,11 @@ #include "InputManager.h" +#include "InteractionEventdataStruct.h" #include "SDL3/SDL_events.h" #include "SDL3/SDL_init.h" #include +#include "SDL3/SDL_stdinc.h" +#include "VEGO.h" +#include "VEGO_Event.h" std::ostream& operator<<(std::ostream& os, InputManager::Key key) { static const std::unordered_map keyToString { @@ -342,14 +346,11 @@ std::string InputManager::getActiveContext() const { } SDL_AppResult InputManager::handleEvent(SDL_EventType type, SDL_Event* const event) { - std::cout << "in handleEvent" << std::endl; if (type != SDL_EVENT_KEY_DOWN) { - std::cout << "ignore key up" << std::endl; return SDL_APP_CONTINUE; } if (event->key.repeat) { - std::cout << "ignore key repeat" << std::endl; return SDL_APP_CONTINUE; } diff --git a/src/InteractionManager.cpp b/src/InteractionManager.cpp new file mode 100644 index 0000000..5c74ae9 --- /dev/null +++ b/src/InteractionManager.cpp @@ -0,0 +1,90 @@ +#include "InteractionManager.h" + +#include "InteractionEventdataStruct.h" +#include "InteractionListener.h" +#include "SDL3/SDL_init.h" +#include "VEGO_Event.h" +#include "Vector2D.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +InteractionManager::InteractionManager() +{ + this->targetingFuncs.fill(nullptr); + this->targetingFuncs.at(static_cast::type>(InteractionManager::TargetingStrategy::closest)) = [](Vector2D* reference, std::vector> input) { + return std::shared_ptr(); + }; + this->targetingFuncs.at(static_cast::type>(InteractionManager::TargetingStrategy::closest)) = [](Vector2D* reference, std::vector> input) { + auto min = std::ranges::min_element(input, [&reference](std::shared_ptr& a, std::shared_ptr& b) { + std::shared_ptr coordA = a->getPosition(); + std::shared_ptr coordB = b->getPosition(); + + if (coordB == nullptr) return true; + if (coordA == nullptr) return false; + + return std::sqrt(std::pow(coordA->x - reference->x, 2) + std::pow(coordA->y - reference->y, 2)) < std::sqrt(std::pow(coordB->x - reference->x, 2) + std::pow(coordB->y - reference->y, 2)); + }); + return min == std::ranges::end(input) ? nullptr : *min; + }; + this->targetingFuncs.at(static_cast::type>(InteractionManager::TargetingStrategy::manhattenDistance)) = [](Vector2D* reference, std::vector> input) { + auto min = std::ranges::min_element(input, [&reference](std::shared_ptr& a, std::shared_ptr& b) { + std::shared_ptr coordA = a->getPosition(); + std::shared_ptr coordB = b->getPosition(); + + if (coordB == nullptr) return true; + if (coordA == nullptr) return false; + + return (std::abs(coordA->x - reference->x) + std::abs(coordA->y - reference->y)) < (std::abs(coordB->x - reference->x) + std::abs(coordB->y - reference->y)); + }); + return min == std::ranges::end(input) ? nullptr : *min; + }; +} + +SDL_AppResult InteractionManager::handleInteract(SDL_EventType type, SDL_Event* const event) +{ + if (type != vego::VEGO_Event_Interaction) { // error handling + return SDL_APP_CONTINUE; + } + + InteractionEventdataStruct* data = static_cast(event->user.data1); + + std::shared_ptr listener = data->target.lock(); + + if (data->strategy != static_cast::type>(InteractionManager::TargetingStrategy::none)) { + listener = this->targetingFuncs.at(data->strategy)( + data->targetingReference.get(), + this->listeners + | std::views::transform(&std::weak_ptr::lock) + | std::views::filter(&std::shared_ptr::operator bool) + | std::ranges::to() + ); + } + + if (listener) { + listener->interact(data->actor, data->data); + } + + return SDL_APP_CONTINUE; +} + +void InteractionManager::registerListener(std::weak_ptr listener) +{ + this->listeners.emplace_back(listener); +} + +uint8_t InteractionManager::registerTargetingFunc(TargetingFunc func) +{ + auto it = std::ranges::find_if(this->targetingFuncs, [](const auto& func) { + return !func; + }); + (*it) = func; + return std::distance(this->targetingFuncs.begin(), it); +} \ No newline at end of file diff --git a/src/PowerupComponent.cpp b/src/PowerupComponent.cpp index 4db3f95..0e16c64 100644 --- a/src/PowerupComponent.cpp +++ b/src/PowerupComponent.cpp @@ -3,9 +3,13 @@ #include "CollisionHandler.h" #include "Entity.h" #include "HealthComponent.h" +#include "SpriteComponent.h" #include "StatEffectsComponent.h" #include "Constants.h" +#include "TextureManager.h" +#include "TransformComponent.h" #include +#include "VEGO.h" PowerupComponent::PowerupComponent(std::function func) { @@ -23,4 +27,16 @@ void PowerupComponent::update(uint_fast16_t diffTime) (this->pickupFunc)(player); this->entity->destroy(); } +} + + +void PowerupComponent::interact(void* actor, void* data) +{ + std::cout << VEGO_Game().textureManager->getTexturePath(this->entity->getComponent().getTexture()) << std::endl; +} + + +std::shared_ptr PowerupComponent::getPosition() +{ + return std::make_shared(this->entity->getComponent().position); } \ No newline at end of file diff --git a/src/RenderObject.cpp b/src/RenderObject.cpp index 5c21ee9..897940e 100644 --- a/src/RenderObject.cpp +++ b/src/RenderObject.cpp @@ -1,10 +1,10 @@ #include "RenderObject.h" #include "RenderManager.h" -RenderObject::RenderObject(int zIndex, RenderManager& renderManager) : zIndex(zIndex), renderManager(renderManager) { - renderManager.add(this); +RenderObject::RenderObject(int zIndex, RenderManager* renderManager) : zIndex(zIndex), renderManager(renderManager) { + renderManager->add(this); } RenderObject::~RenderObject() { - this->renderManager.remove(this); + this->renderManager->remove(this); } \ No newline at end of file diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 0cc29c7..8bd341a 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -18,7 +18,7 @@ SpriteComponent::SpriteComponent(Textures texture, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0) { this->textureEnum = texture; - this->path = ""; + this->path = ""; } SpriteComponent::SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index ee8fceb..02707a7 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -15,6 +15,9 @@ void TextureManager::addSingleTexture(Textures texture, const char* filePath) { SDL_SetTextureScaleMode(sdlTexture, this->scaleMode); // linear scaling results in blurry images this->texture_cache.emplace(texture, sdlTexture); + if (filePath != nullptr) { + this->texture_references.emplace(texture, std::string(filePath)); + } std::cout << "Loaded texture at " << filePath << std::endl; } From 3c5d56de6bc29583cfc31083545a6a15b8db88ae Mon Sep 17 00:00:00 2001 From: Nimac0 Date: Wed, 9 Apr 2025 21:06:34 +0200 Subject: [PATCH 42/42] feat/ref: Interaction and Event management --- include/InputManager.h | 16 ++-- include/InteractionComponent.h | 28 ++++++ include/InteractionEventdataStruct.h | 19 +++- src/EventManager.cpp | 10 +-- src/GameInternal.cpp | 1 + src/InputManager.cpp | 126 +++++---------------------- src/InteractionComponent.cpp | 22 +++++ src/InteractionEventdataStruct.cpp | 16 ++++ src/TransformComponent.cpp | 3 + 9 files changed, 120 insertions(+), 121 deletions(-) create mode 100644 include/InteractionComponent.h create mode 100644 src/InteractionComponent.cpp create mode 100644 src/InteractionEventdataStruct.cpp diff --git a/include/InputManager.h b/include/InputManager.h index ebc6272..8c3b144 100644 --- a/include/InputManager.h +++ b/include/InputManager.h @@ -102,7 +102,7 @@ public: struct InputAction { std::string name; std::vector bindings; - std::function callback; + std::function callback; }; InputManager(); @@ -110,28 +110,26 @@ public: void init(); // see if necessary void processEvents(); - void registerAction(const std::string& actionName, const std::vector& keys, std::function callback, const std::string& context); + void registerAction(const std::string& actionName, const std::vector& keys, std::function callback, const std::string& context); void setActiveContext(const std::string& context); std::string getActiveContext() const; - void rebindAction(const std::string& actionName, const std::vector& newBindings, const std::string& context); - void removeBindings(const std::string& actionName, const std::string& context); - std::vector getBindings(const std::string& actionName, const std::string& context) const; + //void rebindAction(const std::string& actionName, const std::vector& newBindings, const std::string& context); + //void removeBindings(const std::string& actionName, const std::string& context); + //std::vector getBindings(const std::string& actionName, const std::string& context) const; std::vector getActionsByKey(const Key key) const; SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event); + void initKeyMap(); private: // TODO: flesh this out to avoid loops in process actions // additionally to actionsByContext, not instead - std::map> actionsByContext; - std::map> actionsByKey; + std::map>> actionsByContextAndKey; std::map keyMap; std::string activeContext; - - void initKeyMap(); }; std::ostream& operator<<(std::ostream& os, InputManager::Key key); diff --git a/include/InteractionComponent.h b/include/InteractionComponent.h new file mode 100644 index 0000000..d016a6f --- /dev/null +++ b/include/InteractionComponent.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Component.h" +#include "InteractionListener.h" + +#include + +class InteractionComponent : public Component, public InteractionListener +{ +public: + /** + * @brief Constructor for the InteractionComponent. + * @param callback A function to be called when an interaction event is triggered. void* actor, void* data are passed to the callback function from InteractionEventdataStruct. + */ + InteractionComponent(std::function callback); + + /** + * @brief Internal function to be called when an interaction event is triggered. + */ + void interact(void* actor, void* data) override; + + /** + * @brief Internal function to use as reference for targeting. + */ + std::shared_ptr getPosition() override; +private: + std::function interactionCallback; +}; \ No newline at end of file diff --git a/include/InteractionEventdataStruct.h b/include/InteractionEventdataStruct.h index 036f03c..759bbb8 100644 --- a/include/InteractionEventdataStruct.h +++ b/include/InteractionEventdataStruct.h @@ -2,14 +2,27 @@ #include "Entity.h" #include "InteractionListener.h" +#include "InteractionManager.h" #include "Vector2D.h" #include #include +/** + * @brief Struct to hold data for interaction events. + * This struct is used to pass data to the interaction manager when an interaction event is triggered. + */ struct InteractionEventdataStruct { - void* actor; // suggestion, can also be used for other arbitrary data + /// Arbitray data to pass to the interaction listener. Can for example be an Entity ptr to represent the actor. + void* actor; + /// The data to pass to the interaction listener. Can be any type of pointer. void* data; + /// The target of the interaction, e.g. InteractionComponent of an Entity. Is required if strategy is set to 0 (none) std::weak_ptr target = std::weak_ptr(); - std::shared_ptr targetingReference; // required without explicit target - uint8_t strategy = 0; // required without explicit target, defaults to none + /// Coordinates from which to base targeting on. Is required if strategy is not set to 0 (none) + std::shared_ptr targetingReference = nullptr; + /// required without explicit target, defaults to none + /// @sa InteractionManager::TargetingStrategy + uint8_t strategy = 0; // int since enum would be impossibling user defined targetingStrategies + + void triggerEvent(); }; \ No newline at end of file diff --git a/src/EventManager.cpp b/src/EventManager.cpp index 049a8b0..717f072 100644 --- a/src/EventManager.cpp +++ b/src/EventManager.cpp @@ -12,11 +12,11 @@ Uint32 vego::VEGO_Event_Interaction; EventManager::EventManager() { - /// \TODO: from c++26 you (should be able to) can get the amount of name values in an enum vego::VEGO_Event_Interaction = SDL_RegisterEvents(1); // TODO: error handling } + void EventManager::registerListener(EventListener listener, std::initializer_list eventTypes) { std::ranges::for_each(eventTypes.begin(), eventTypes.end(), [this, &listener](const Uint32& eventType) { @@ -31,10 +31,10 @@ SDL_AppResult EventManager::handleEvent(SDL_Event* event) { SDL_EventType type = (SDL_EventType) event->type; if (this->eventListeners.contains(type)) { - auto results = this->eventListeners.at(type) | std::views::transform( - [&event](EventListener listener) { - return listener((SDL_EventType) event->type, event); - }); + std::vector results; + for (auto& listener : this->eventListeners.at(type)) { + results.emplace_back(listener((SDL_EventType) event->type, event)); + } if (std::ranges::contains(results, SDL_APP_FAILURE)) return SDL_APP_FAILURE; if (std::ranges::contains(results, SDL_APP_SUCCESS)) diff --git a/src/GameInternal.cpp b/src/GameInternal.cpp index d4aea1a..30ec531 100644 --- a/src/GameInternal.cpp +++ b/src/GameInternal.cpp @@ -50,6 +50,7 @@ SDL_AppResult GameInternal::init() GameInternal::soundManager = new SoundManager(); GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer? GameInternal::inputManager = new InputManager(); + GameInternal::inputManager->initKeyMap(); GameInternal::renderManager = new RenderManager(); GameInternal::eventManager = new EventManager(); diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 6542ec3..519df21 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -101,12 +101,8 @@ std::ostream& operator<<(std::ostream& os, InputManager::Key key) { std::ostream& operator<<(std::ostream& os, const InputManager::InputAction& action) { os << action.name << " with binding(s): "; - for (size_t i = 0; i < action.bindings.size(); ++i) { - os << action.bindings[i]; - - if (i < action.bindings.size() - 1) { - os << ", "; - } + for (auto& binding : action.bindings) { + os << binding << ", "; } return os; } @@ -168,13 +164,6 @@ InputManager::InputManager() : activeContext("Default") {} InputManager::~InputManager() {} -void InputManager::init() { - if (SDL_Init(SDL_INIT_EVENTS) != 0) { - std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl; - return; - } -} - void InputManager::initKeyMap() { keyMap = { {Key::UP, SDL_SCANCODE_UP}, @@ -259,81 +248,25 @@ void InputManager::initKeyMap() { }; } -void InputManager::registerAction(const std::string& actionName, const std::vector& keys, std::function callback, const std::string& context) { - actionsByContext[context].emplace_back(actionName, keys, callback); - InputAction& storedAction = actionsByContext[context].back(); +void InputManager::registerAction(const std::string& actionName, const std::vector& keys, std::function callback, const std::string& context) { + InputAction* storedAction = new InputAction{actionName, keys, callback}; for (const auto& key : keys) { - actionsByKey[key].push_back(&storedAction); + actionsByContextAndKey[context][key].emplace_back(storedAction); } std::cout << "Registered action: " << storedAction << " in context: " << context << std::endl; } -void InputManager::rebindAction(const std::string& actionName, const std::vector& newBindings, const std::string& context) { - auto it = actionsByContext.find(context); - if (it != actionsByContext.end()) { - for (auto& action : it->second) { - if (action.name == actionName) { - for (const auto& key : action.bindings) { - auto& keyActions = actionsByKey[key]; - keyActions.erase(std::remove(keyActions.begin(), keyActions.end(), &action), keyActions.end()); - if (keyActions.empty()) { - actionsByKey.erase(key); - } - } - - action.bindings = newBindings; - - for (const auto& key : newBindings) { - actionsByKey[key].push_back(&action); - } - - std::cout << "Rebound action: " << actionName << " in context: " << context << " to new bindings: "; - for (const auto& key : newBindings) { - std::cout << key << " "; - } - std::cout << std::endl; - return; - } - } - } - std::cout << "Action not found: " << actionName << " in context: " << context << std::endl; -} - -void InputManager::removeBindings(const std::string& actionName, const std::string& context) { - auto it = actionsByContext.find(context); - if (it != actionsByContext.end()) { - for (auto& action : it->second) { - if (action.name == actionName) { - action.bindings.clear(); - std::cout << "Removed bindings for action: " << actionName << " in context: " << context << std::endl; - return; - } - } - } - std::cout << "Action not found: " << actionName << " in context: " << context << std::endl; -} - -std::vector InputManager::getBindings(const std::string& actionName, const std::string& context) const { - auto it = actionsByContext.find(context); - if (it != actionsByContext.end()) { - for (const auto& action : it->second) { - if (action.name == actionName) { - return action.bindings; - } - } - } - std::cout << "Action not found: " << actionName << " in context: " << context << "\n"; - return {}; -} - std::vector InputManager::getActionsByKey(const Key key) const { - auto it = actionsByKey.find(key); - if (it != actionsByKey.end()) { - std::cout << "DEBUG: Found " << it->second.size() << " actions for key " << key << std::endl; - return it->second; + std::vector result; + + for (const auto& [context, keyMap] : actionsByContextAndKey) { + auto it = keyMap.find(key); + if (it != keyMap.end()) { + result.insert(result.end(), it->second.begin(), it->second.end()); + } } - std::cout << "DEBUG: No actions found for key " << key << std::endl; - return {}; + + return result; } void InputManager::setActiveContext(const std::string& context) { @@ -346,37 +279,22 @@ std::string InputManager::getActiveContext() const { } SDL_AppResult InputManager::handleEvent(SDL_EventType type, SDL_Event* const event) { - if (type != SDL_EVENT_KEY_DOWN) { - return SDL_APP_CONTINUE; - } - if (event->key.repeat) { return SDL_APP_CONTINUE; } - - auto keyIt = std::ranges::find_if(keyMap, - [&](const auto& pair) { return pair.second == event->key.scancode; }); + auto keyIt = std::ranges::find_if(keyMap, [&](const auto& pair) + { return pair.second == event->key.scancode; }); if (keyIt != keyMap.end()) { std::cout << "in != keymap.end" << std::endl; Key pressedKey = keyIt->first; - auto actionIt = actionsByKey.find(pressedKey); - if (actionIt != actionsByKey.end()) { - std::cout << "in != actionsByKey.end" << std::endl; - - for (auto* action : actionIt->second) { - std::cout << "before if(action)" << std::endl; - if (action) { - std::cout << "after if(action)" << std::endl; - - auto& activeActions = actionsByContext[activeContext]; - if (std::ranges::find_if(activeActions, - [&](const InputAction& act) { return &act == action; }) != activeActions.end()) { - std::cout << "Action triggered: " << action->name << " in context: " << activeContext << std::endl; - action->callback(); - } - } + auto keyActions = actionsByContextAndKey[activeContext]; + auto it = keyActions.find(pressedKey); + if (it != keyActions.end()) { + for (auto& action : it->second) { + std::cout << "Action triggered: " << action->name << " in context: " << activeContext << std::endl; + action->callback(type == SDL_EVENT_KEY_UP); } } } diff --git a/src/InteractionComponent.cpp b/src/InteractionComponent.cpp new file mode 100644 index 0000000..bd69ecb --- /dev/null +++ b/src/InteractionComponent.cpp @@ -0,0 +1,22 @@ +#include "InteractionComponent.h" + +#include "VEGO.h" + +InteractionComponent::InteractionComponent(std::function callback) : interactionCallback(callback) +{ + VEGO_Game().interactionManager->registerListener(this->entity->getComponentAsPointer()); +} + +void InteractionComponent::interact(void* actor, void* data) +{ + if (interactionCallback) { + interactionCallback(actor, data); + } +} +std::shared_ptr InteractionComponent::getPosition() // required for targeting strategy, return null to only allow explicit targeting +{ + if (entity->hasComponent()) { + return std::make_shared(entity->getComponent().position); + } + return nullptr; +} \ No newline at end of file diff --git a/src/InteractionEventdataStruct.cpp b/src/InteractionEventdataStruct.cpp new file mode 100644 index 0000000..bdbb81a --- /dev/null +++ b/src/InteractionEventdataStruct.cpp @@ -0,0 +1,16 @@ +#include "InteractionEventdataStruct.h" + +#include "VEGO.h" +#include "VEGO_Event.h" + +void InteractionEventdataStruct::triggerEvent() +{ + // TODO: if target is null && strategy is 0, error + + SDL_Event event; + SDL_zero(event); + event.type = vego::VEGO_Event_Interaction; + event.user.data1 = this; + + SDL_PushEvent(&event); +} \ No newline at end of file diff --git a/src/TransformComponent.cpp b/src/TransformComponent.cpp index 12e5ff2..a67dd1d 100644 --- a/src/TransformComponent.cpp +++ b/src/TransformComponent.cpp @@ -42,6 +42,9 @@ void TransformComponent::init() void TransformComponent::update(uint_fast16_t diffTime) { + direction.x = direction.x > 0 ? 1 : direction.x < 0 ? -1 : 0; + direction.y = direction.y > 0 ? 1 : direction.y < 0 ? -1 : 0; + float multiplier = direction.x != 0 && direction.y != 0 ? 0.707 : 1; // normalizes vector; only works if directions are in increments of 45° Vector2D positionChange( direction.x * this->getSpeed() * multiplier * diffTime * (1.f/1000),