/********************\ | Copyright 2024, | | Ulysse Cura | \********************/ //////////////////////////////////////// // // // Definition de la classe TileMap. // // // //////////////////////////////////////// #include #include #include "Camera.hpp" #include "Game.hpp" #include "MapManager.hpp" #include "TextureManager.hpp" #include "TileMap.hpp" #include "Vector2D.hpp" #include "ECS/Components.hpp" using std::string, std::exception, std::vector, std::cerr, std::runtime_error; using json = nlohmann::json; // Load a map from memory void TileMap::LoadTileMap(const string &path) { // Load the map data from memory json *mapData = Game::mapManager.LoadMap(path); // Get tilemap width and height same for world tileMapWidth = mapData->at("TileMapWidth").get(); tileMapHeight = mapData->at("TileMapHeight").get(); worldWidth = tileMapWidth * TILE_SIZE * TILEMAP_SCALE; worldHeight = tileMapHeight * TILE_SIZE * TILEMAP_SCALE; // Clear layers and hitboxes and resize them m_tilesLayer1.clear(); m_tilesLayer2.clear(); m_tilesLayer3.clear(); hitboxes.clear(); m_tilesLayer1.resize(tileMapWidth * tileMapHeight); m_tilesLayer2.resize(tileMapWidth * tileMapHeight); m_tilesLayer3.resize(tileMapWidth * tileMapHeight); hitboxes.resize(tileMapWidth * tileMapHeight); // Load layers and hitboxes from map data string layers[] {"Layer 1","Layer 2","Layer 3", "Hitboxes"}; for(const string &layer : layers) { for(int y {0}; y < tileMapHeight; y++) { for(int x {0}; x < tileMapWidth; x++) { TileID tileID {mapData->at(layer).at(y).at(x)}; if(layer == "Layer 1") { m_tilesLayer1[x + y * tileMapWidth] = tileID; } else if(layer == "Layer 2") { m_tilesLayer2[x + y * tileMapWidth] = tileID; } else if(layer == "Layer 3") { m_tilesLayer3[x + y * tileMapWidth] = tileID; } else if(layer == "Hitboxes") { hitboxes[x + y * tileMapWidth] = tileID; } } } } LoadEntities(mapData); if(mapData->contains("PlayerInitPos")) { m_playerInitPos.x = mapData->at("PlayerInitPos").at("x").get() * TILE_SIZE * TILEMAP_SCALE; m_playerInitPos.y = mapData->at("PlayerInitPos").at("y").get() * TILE_SIZE * TILEMAP_SCALE; } m_nextMaps.clear(); for(auto it {mapData->at("NextMaps").begin()}; it < mapData->at("NextMaps").end(); it++) { NextMap nextMap; nextMap.path = it->at("Path").get(); nextMap.playerInitPos.x = it->at("PlayerInitPos").at("x").get(); nextMap.playerInitPos.y = it->at("PlayerInitPos").at("y").get(); m_nextMaps.emplace(it->at("Number").get(), nextMap); } // Texture renderer creating if(Game::textureRenderer != NULL) SDL_DestroyTexture(Game::textureRenderer); Game::textureRenderer = SDL_CreateTexture(Game::renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, worldWidth, worldHeight); if(Game::textureRenderer == NULL) { cerr << "Erreur SDL_CreateTexture : " << SDL_GetError() << '\n'; throw runtime_error("Impossible de creer la texture de rendu.\n"); } } void TileMap::LoadEntities(json *mapData) { // Erase lasts entities and load news if there are some std::size_t numberOfEntity {Game::entityManager.getNumberOfEntity()}; for(std::size_t i {1}; i < numberOfEntity; i++) Game::entityManager.destroy(i); Game::entityManager.refresh(); if(mapData->contains("Entities")) { for(auto it {mapData->at("Entities").begin()}; it < mapData->at("Entities").end(); it++) { Entity &e(Game::entityManager.addEntity()); for(auto component {it->begin()}; component < it->end(); component++) { if(component->at("Type").get() == "TransformComponent") { Vector2D pos {Vector2D(component->at("Position").at("x").get(), component->at("Position").at("y").get())}; Vector2D dim {Vector2D(component->at("Dimension").at("x").get(), component->at("Dimension").at("y").get())}; pos = pos * TILE_SIZE * TILEMAP_SCALE; e.addComponent(pos, dim, component->at("Scale").get(), component->at("Speed").get()); } else if(component->at("Type").get() == "SpriteComponent") { e.addComponent(component->at("Path").get()); } else if(component->at("Type").get() == "AnimationSystem") { int nbFrames {component->at("NbFrames").get()}; int currentFrame {component->at("CurrentFrame").get()}; int frameDelay {component->at("FrameDelay").get()}; bool playAnimation {component->at("PlayAnimation").get()}; e.addComponent(nbFrames, currentFrame, frameDelay, playAnimation); } else if(component->at("Type").get() == "HitboxComponent") { Vector2D sc {Vector2D(component->at("Scale").at("x").get(), component->at("Scale").at("y").get())}; Vector2D pos {Vector2D(component->at("Position").at("x").get(), component->at("Position").at("y").get())}; e.addComponent(sc, pos); } else if(component->at("Type").get() == "Lever") { e.addComponent(component->at("Channel").get()); } else if(component->at("Type").get() == "Lock") { e.addComponent(component->at("Channel").get()); } else if(component->at("Type").get() == "Door") { unordered_map states {}; for(auto state {component->at("States").begin()}; state < component->at("States").end(); state++) states[state->at("Channel").get()] = state->at("State").get(); e.addComponent(states); } } } } Game::entityManager.update(); // Texture renderer creating if(Game::textureRenderer != NULL) SDL_DestroyTexture(Game::textureRenderer); Game::textureRenderer = SDL_CreateTexture(Game::renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, worldWidth, worldHeight); if(Game::textureRenderer == NULL) { cerr << "Erreur SDL_CreateTexture : " << SDL_GetError() << '\n'; throw runtime_error("Impossible de creer la texture de rendu.\n"); } } // Load the corresponding next map from memory void TileMap::LoadNextMap(int nextMapNumber) { NextMap nextMap = m_nextMaps.at(nextMapNumber); LoadTileMap(nextMap.path); m_playerInitPos = nextMap.playerInitPos * TILE_SIZE * TILEMAP_SCALE; } // Load a tileset void TileMap::LoadTileset(const string &path) { m_tileset = Game::textureManager.LoadTexture(path); SDL_QueryTexture(m_tileset, nullptr, nullptr, &m_tilesetWidth, &m_tilesetHeight); m_tilesetWidth /= TILE_SIZE; m_tilesetHeight /= TILE_SIZE; } // Draw corresponding layer void TileMap::draw(int layer) { if(layer == 1) { m_draw(m_tilesLayer1); } else if(layer == 2) { m_draw(m_tilesLayer2); } else if(layer == 3) { m_draw(m_tilesLayer3); } else { cerr << "Erreur : La tileMap " << layer << " n'est pas prise en charge.\n"; throw runtime_error("Impossible de dessiner la tileMap.\n"); } } // Draw the layer given void TileMap::m_draw(const vector &tiles) { SDL_Rect visibleTilesR; visibleTilesR.x = Game::camera.camR.x / (TILE_SIZE * TILEMAP_SCALE); visibleTilesR.y = Game::camera.camR.y / (TILE_SIZE * TILEMAP_SCALE); visibleTilesR.w = (Game::camera.camR.w + Game::camera.camR.x) / (TILE_SIZE * TILEMAP_SCALE); visibleTilesR.h = (Game::camera.camR.h + Game::camera.camR.y) / (TILE_SIZE * TILEMAP_SCALE); for(int tileY {visibleTilesR.y}; tileY <= visibleTilesR.h; tileY++) { for(int tileX {visibleTilesR.x}; tileX <= visibleTilesR.w; tileX++) { const TileID tile = tiles[tileX + tileY * tileMapWidth] - 1; if(tile) { SDL_Rect srcR {(tile % m_tilesetWidth) * TILE_SIZE, (tile / m_tilesetWidth) * TILE_SIZE, TILE_SIZE, TILE_SIZE}; SDL_Rect dstR {tileX * TILE_SIZE * TILEMAP_SCALE, tileY * TILE_SIZE * TILEMAP_SCALE, TILE_SIZE * TILEMAP_SCALE, TILE_SIZE * TILEMAP_SCALE}; Game::textureManager.Draw(m_tileset, srcR, dstR, false); } } } } // Get loaded player inital position Vector2D TileMap::getPlayerInitPos() { return m_playerInitPos; } // Destroy texture renderer TileMap::~TileMap() { if(Game::textureRenderer != NULL) SDL_DestroyTexture(Game::textureRenderer); }