diff --git a/.gitmodules b/.gitmodules index bfa520c..6e8ab27 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/tmxlite"] + path = extern/tmxlite + url = https://github.com/fallahn/tmxlite.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 5149005..602370b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,10 +17,13 @@ set(SDL2TTF_VENDORED ON) set(SDL2_SOURCE_DIR “${ENGINE_SOURCE_DIR}/extern/SDL”) +set(TMXLITE_STATIC_LIB TRUE) + 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/tmxlite/tmxlite EXCLUDE_FROM_ALL) file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) add_library(${PROJECT_NAME} ${SOURCES}) @@ -33,6 +36,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 + tmxlite ) if(CMAKE_BUILD_TYPE MATCHES "Debug") diff --git a/extern/tmxlite b/extern/tmxlite new file mode 160000 index 0000000..fcef1a2 --- /dev/null +++ b/extern/tmxlite @@ -0,0 +1 @@ +Subproject commit fcef1a28ade8406e290d5fd168a8950e6996844f diff --git a/include/Map.h b/include/Map.h index 4c1bc3b..55a8527 100644 --- a/include/Map.h +++ b/include/Map.h @@ -23,4 +23,6 @@ public: */ 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 loadMapTmx(const char* path); }; diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index b1f3a32..0676549 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -31,8 +31,12 @@ private: uint8_t speed = 100; bool flipped = false; + int textureXOffset; + int textureYOffset; + public: SpriteComponent(const char* path, int zIndex); + SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex); SpriteComponent( const char* path, bool isAnimated, diff --git a/src/Map.cpp b/src/Map.cpp index 5689d9e..4b971a6 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -1,14 +1,28 @@ #include "Map.h" +#include #include #include #include +#include #include +#include + +#include +#include + +#include +#include +#include +#include +#include #include "Constants.h" #include "GameInternal.h" -#include "SDL_error.h" +#include "SpriteComponent.h" +#include "TextureManager.h" #include "TileComponent.h" +#include "VEGO.h" void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, const std::map>* textureDict /* backreference */) { @@ -36,7 +50,7 @@ void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, co 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(); + SDL_ClearError(); } x = 0; y++; @@ -58,9 +72,96 @@ void Map::loadMap(const char* path, int sizeX, int sizeY, GameInternal* game, co void Map::addTile(unsigned long id, int x, int y, GameInternal* game, const std::map>* textureDict) // tile entity { + printf("X: %d, Y: %d", x, y); + 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); +} + +void Map::loadMapTmx(const char* path) +{ + tmx::Map map; + if (!map.load(path)) { + // TODO: log to console + } + + 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) { + texturePaths.emplace_back(tileSet.getImagePath()); + } + + for (auto& layer : mapLayers) { + + 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"; + }); + + if (zIndexIterator != properties.end() && std::is_samegetType()), int>::value) { + zIndex = zIndexIterator->getIntValue(); + } + + const auto& tiles = tileLayer.getTiles(); + + for (auto i = 0u; i < tileSets.size(); i++) { + auto tilesetTexture = VEGO_Game().textureManager->loadTexture(texturePaths.at(i).c_str()); + int texX, texY; + SDL_QueryTexture(tilesetTexture, nullptr, nullptr, &texX, &texY); + + const auto tileCountX = texX / mapTileSize.x; + const auto tileCountY = texY / mapTileSize.y; + + for (auto y = 0u; y < mapSize.y; ++y) { + for (auto x = 0u; x < mapSize.x; ++x) { + const auto idx = y * mapSize.x + x; + if (idx < tiles.size() && tiles[idx].ID >= tileSets.at(i).getFirstGID() + && tiles[idx].ID < (tileSets.at(i).getFirstGID() + tileSets.at(i).getTileCount())) { + + 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 /= texX; + v /= texY; + + //vert pos + const float tilePosX = static_cast(x) * mapTileSize.x; + const float tilePosY = (static_cast(y) * mapTileSize.y); + + auto& tile(VEGO_Game().manager.addEntity()); + + tile.addComponent(tilePosX, tilePosY, mapTileSize.x, mapTileSize.y, 1); + tile.addComponent(texturePaths.at(i).c_str(), v, u, zIndex); // why does uv need to be reversed? + + } + } + } + } + + continue; + } + if (layer->getType() == tmx::Layer::Type::Object) { + // spawn objects + continue; + } + } } \ No newline at end of file diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index 6c1963d..b62c148 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -15,7 +15,12 @@ #include "Manager.h" #include "VEGO.h" -SpriteComponent::SpriteComponent(const char* path, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager) +SpriteComponent::SpriteComponent(const char* path, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0) +{ + this->texturePath = path; +} + +SpriteComponent::SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) { this->texturePath = path; } @@ -25,7 +30,7 @@ SpriteComponent::SpriteComponent( bool isAnimated, std::map>* animationMap, std::string defaultAnimation, - int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager) + int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0) { animated = isAnimated; @@ -49,21 +54,16 @@ void SpriteComponent::init() this->transform = &entity->getComponent(); - this->srcRect.x = this->srcRect.y = 0; this->srcRect.w = transform->width; this->srcRect.h = transform->height; + this->srcRect.x = this->textureXOffset * this->srcRect.w; + this->srcRect.y = this->textureYOffset * this->srcRect.h;; this->update(); } void SpriteComponent::update() { - if (animated) { - srcRect.x = srcRect.w * static_cast((SDL_GetTicks() / speed) % frames); - } - - srcRect.y = animationIndex * transform->height; - this->destRect.x = this->transform->position.x; this->destRect.y = this->transform->position.y; this->destRect.w = transform->width * transform->scale;