267 lines
9.5 KiB
C++
267 lines
9.5 KiB
C++
/********************\
|
|
| Copyright 2024, |
|
|
| Ulysse Cura |
|
|
\********************/
|
|
|
|
////////////////////////////////////////
|
|
// //
|
|
// Definition de la classe TileMap. //
|
|
// //
|
|
////////////////////////////////////////
|
|
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
#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<int>();
|
|
tileMapHeight = mapData->at("TileMapHeight").get<int>();
|
|
|
|
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<float>() * TILE_SIZE * TILEMAP_SCALE;
|
|
m_playerInitPos.y = mapData->at("PlayerInitPos").at("y").get<float>() * 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<string>();
|
|
nextMap.playerInitPos.x = it->at("PlayerInitPos").at("x").get<float>();
|
|
nextMap.playerInitPos.y = it->at("PlayerInitPos").at("y").get<float>();
|
|
|
|
m_nextMaps.emplace(it->at("Number").get<int>(), 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<string>() == "TransformComponent")
|
|
{
|
|
Vector2D<float> pos {Vector2D<float>(component->at("Position").at("x").get<float>(), component->at("Position").at("y").get<float>())};
|
|
Vector2D<float> dim {Vector2D<float>(component->at("Dimension").at("x").get<float>(), component->at("Dimension").at("y").get<float>())};
|
|
|
|
pos = pos * TILE_SIZE * TILEMAP_SCALE;
|
|
|
|
e.addComponent<TransformComponent>(pos, dim, component->at("Scale").get<int>(), component->at("Speed").get<float>());
|
|
}
|
|
else if(component->at("Type").get<string>() == "SpriteComponent")
|
|
{
|
|
e.addComponent<SpriteComponent>(component->at("Path").get<string>());
|
|
}
|
|
else if(component->at("Type").get<string>() == "AnimationSystem")
|
|
{
|
|
int nbFrames {component->at("NbFrames").get<int>()};
|
|
int currentFrame {component->at("CurrentFrame").get<int>()};
|
|
int frameDelay {component->at("FrameDelay").get<int>()};
|
|
bool playAnimation {component->at("PlayAnimation").get<bool>()};
|
|
|
|
e.addComponent<AnimationSystem>(nbFrames, currentFrame, frameDelay, playAnimation);
|
|
}
|
|
else if(component->at("Type").get<string>() == "HitboxComponent")
|
|
{
|
|
Vector2D<float> sc {Vector2D<float>(component->at("Scale").at("x").get<float>(), component->at("Scale").at("y").get<float>())};
|
|
Vector2D<float> pos {Vector2D<float>(component->at("Position").at("x").get<float>(), component->at("Position").at("y").get<float>())};
|
|
|
|
e.addComponent<HitboxComponent>(sc, pos);
|
|
}
|
|
else if(component->at("Type").get<string>() == "Lever")
|
|
{
|
|
e.addComponent<Lever>(component->at("Channel").get<int>());
|
|
}
|
|
else if(component->at("Type").get<string>() == "Lock")
|
|
{
|
|
e.addComponent<Lock>(component->at("Channel").get<int>());
|
|
}
|
|
else if(component->at("Type").get<string>() == "Door")
|
|
{
|
|
unordered_map<int, bool> states {};
|
|
|
|
for(auto state {component->at("States").begin()}; state < component->at("States").end(); state++)
|
|
states[state->at("Channel").get<int>()] = state->at("State").get<bool>();
|
|
|
|
e.addComponent<Door>(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<TileID> &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<float> TileMap::getPlayerInitPos()
|
|
{
|
|
return m_playerInitPos;
|
|
}
|
|
|
|
// Destroy texture renderer
|
|
TileMap::~TileMap()
|
|
{
|
|
if(Game::textureRenderer != NULL) SDL_DestroyTexture(Game::textureRenderer);
|
|
}
|