742 lines
21 KiB
C++
742 lines
21 KiB
C++
#include "map.h"
|
|
|
|
// Constructor
|
|
Map::Map(std::string file, SDL_Renderer *renderer, Asset *asset, ItemTracker *itemTracker)
|
|
{
|
|
// Inicializa variables
|
|
tile_size = 8;
|
|
map_width = 40;
|
|
map_height = 30;
|
|
name = file.substr(file.find_last_of("\\/") + 1);
|
|
enemy_file = "";
|
|
bgColor1 = bgColor2 = {0, 0, 0};
|
|
bgScroll = false;
|
|
counter = 0;
|
|
|
|
// Copia los punteros a objetos
|
|
this->asset = asset;
|
|
this->renderer = renderer;
|
|
this->itemTracker = itemTracker;
|
|
|
|
// Crea los objetos
|
|
load(file);
|
|
texture_tile = new LTexture(renderer, asset->get(tileset_img));
|
|
tileset_width = texture_tile->getWidth() / tile_size;
|
|
|
|
// Crea las texturas para dibujar el mapa
|
|
map_layer0 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT);
|
|
if (map_layer0 == NULL)
|
|
printf("Error: map_layer0 could not be created!\nSDL Error: %s\n", SDL_GetError());
|
|
|
|
map_layer1 = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT);
|
|
if (map_layer1 == NULL)
|
|
printf("Error: map_layer1 could not be created!\nSDL Error: %s\n", SDL_GetError());
|
|
|
|
// Pinta el mapa en las texturas
|
|
fillMapTexture();
|
|
}
|
|
|
|
// Destructor
|
|
Map::~Map()
|
|
{
|
|
// Reclama la memoria utilizada por los objetos
|
|
texture_tile->unload();
|
|
delete texture_tile;
|
|
|
|
SDL_DestroyTexture(map_layer1);
|
|
|
|
for (auto actor : actors)
|
|
{
|
|
delete actor;
|
|
}
|
|
actors.clear();
|
|
}
|
|
|
|
// Carga las variables desde un fichero
|
|
bool Map::load(std::string file_path)
|
|
{
|
|
// Indicador de éxito en la carga
|
|
bool success = true;
|
|
|
|
std::string filename = file_path.substr(file_path.find_last_of("\\/") + 1);
|
|
std::string line;
|
|
std::ifstream file(file_path);
|
|
|
|
// El fichero se puede abrir
|
|
if (file.good())
|
|
{
|
|
// Procesa el fichero linea a linea
|
|
printf("Reading file %s\n\n", filename.c_str());
|
|
while (std::getline(file, line))
|
|
{
|
|
// Si la linea contiene el texto [tilemap] se realiza el proceso de carga del fichero tmx
|
|
if (line == "[tilemap]")
|
|
{
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
if (line.find(".tmx") != std::string::npos)
|
|
{
|
|
std::ifstream file2(asset->get(line)); // Abre el fichero tmx
|
|
if (file2.good())
|
|
{
|
|
bool map_col_read = false;
|
|
bool map_l0_read = false;
|
|
bool map_l1_read = false;
|
|
while (std::getline(file2, line)) // Lee el fichero linea a linea
|
|
{
|
|
if (!map_l0_read)
|
|
{ // Lee lineas hasta que encuentre donde empiezan los datos del mapa
|
|
int pos = 0;
|
|
do
|
|
{
|
|
std::getline(file2, line);
|
|
pos = line.find("data encoding");
|
|
} while (pos == std::string::npos);
|
|
|
|
do
|
|
{ // Se introducen los valores separados por comas en un vector
|
|
map_l0_read = true;
|
|
std::getline(file2, line);
|
|
if (line != "</data>")
|
|
{
|
|
std::stringstream ss(line);
|
|
std::string tmp;
|
|
while (getline(ss, tmp, ','))
|
|
{
|
|
tilemap_l0.push_back(std::stoi(tmp));
|
|
}
|
|
}
|
|
} while (line != "</data>");
|
|
}
|
|
|
|
if (!map_l1_read)
|
|
{ // Lee lineas hasta que encuentre donde empiezan los datos del mapa
|
|
int pos = 0;
|
|
do
|
|
{
|
|
std::getline(file2, line);
|
|
pos = line.find("data encoding");
|
|
} while (pos == std::string::npos);
|
|
|
|
do
|
|
{ // Se introducen los valores separados por comas en un vector
|
|
map_l1_read = true;
|
|
std::getline(file2, line);
|
|
if (line != "</data>")
|
|
{
|
|
std::stringstream ss(line);
|
|
std::string tmp;
|
|
while (getline(ss, tmp, ','))
|
|
{
|
|
tilemap_l1.push_back(std::stoi(tmp));
|
|
}
|
|
}
|
|
} while (line != "</data>");
|
|
}
|
|
|
|
if (!map_col_read)
|
|
{ // Lee lineas hasta que encuentre donde empiezan los datos del mapa
|
|
int pos = 0;
|
|
do
|
|
{
|
|
std::getline(file2, line);
|
|
pos = line.find("data encoding");
|
|
} while (pos == std::string::npos);
|
|
|
|
do
|
|
{ // Se introducen los valores separados por comas en un vector
|
|
map_col_read = true;
|
|
std::getline(file2, line);
|
|
if (line != "</data>")
|
|
{
|
|
std::stringstream ss(line);
|
|
std::string tmp;
|
|
while (getline(ss, tmp, ','))
|
|
{
|
|
collisionmap.push_back(std::stoi(tmp));
|
|
}
|
|
}
|
|
} while (line != "</data>");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (line != "[/tilemap]");
|
|
}
|
|
|
|
// Si la linea contiene el texto [actor] se realiza el proceso de carga de los actores
|
|
else if (line == "[actors]")
|
|
{
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
|
|
if (line == "[moving platform]")
|
|
{
|
|
actor_t actor;
|
|
actor.asset = asset;
|
|
actor.renderer = renderer;
|
|
actor.name = a_moving_platform;
|
|
SDL_Point p1, p2;
|
|
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
|
|
// Procesa las dos subcadenas
|
|
if (!setActor(&actor, &p1, &p2, line.substr(0, pos), line.substr(pos + 1, line.length())))
|
|
{
|
|
printf("Warning: file %s\n, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
|
|
success = false;
|
|
}
|
|
|
|
} while (line != "[/moving platform]");
|
|
|
|
printf("** actor moving platform loaded\n\n");
|
|
actors.push_back(new ActorMovingPlatform(actor, p1, p2));
|
|
}
|
|
|
|
if (line == "[diamond]")
|
|
{
|
|
actor_t actor;
|
|
actor.asset = asset;
|
|
actor.renderer = renderer;
|
|
actor.name = a_diamond;
|
|
actor.vx = 0.0f;
|
|
actor.vy = 0.0f;
|
|
SDL_Point p1, p2;
|
|
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
|
|
// Procesa las dos subcadenas
|
|
if (!setActor(&actor, &p1, &p2, line.substr(0, pos), line.substr(pos + 1, line.length())))
|
|
{
|
|
printf("Warning: file %s\n, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
|
|
success = false;
|
|
}
|
|
|
|
} while (line != "[/diamond]");
|
|
|
|
// Comprueba si el actor no ha sido recogido previamente
|
|
if (!itemTracker->hasBeenPicked(name, {(int)actor.x, (int)actor.y}))
|
|
{
|
|
printf("** actor diamond loaded\n\n");
|
|
actors.push_back(new ActorDiamond(actor));
|
|
}
|
|
}
|
|
|
|
} while (line != "[/actors]");
|
|
}
|
|
|
|
// En caso contrario se parsea el fichero para buscar las variables y los valores
|
|
else
|
|
{
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
// Procesa las dos subcadenas
|
|
if (!setVars(line.substr(0, pos), line.substr(pos + 1, line.length())))
|
|
{
|
|
printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
|
|
success = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cierra el fichero
|
|
printf("Closing file %s\n\n", filename.c_str());
|
|
file.close();
|
|
}
|
|
// El fichero no se puede abrir
|
|
else
|
|
{
|
|
printf("Warning: Unable to open %s file\n", filename.c_str());
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Asigna variables a partir de dos cadenas
|
|
bool Map::setVars(std::string var, std::string value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (var == "tileset_img")
|
|
{
|
|
tileset_img = value;
|
|
}
|
|
|
|
else if (var == "bgColor1")
|
|
{
|
|
// Se introducen los valores separados por comas en un vector
|
|
std::stringstream ss(value);
|
|
std::string tmp;
|
|
getline(ss, tmp, ',');
|
|
bgColor1.r = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
bgColor1.g = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
bgColor1.b = std::stoi(tmp);
|
|
}
|
|
|
|
else if (var == "bgColor2")
|
|
{
|
|
// Se introducen los valores separados por comas en un vector
|
|
std::stringstream ss(value);
|
|
std::string tmp;
|
|
getline(ss, tmp, ',');
|
|
bgColor2.r = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
bgColor2.g = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
bgColor2.b = std::stoi(tmp);
|
|
}
|
|
|
|
else if (var == "bgScroll")
|
|
{
|
|
bgScroll = stringToBool(value);
|
|
}
|
|
|
|
else if (var == "room_up")
|
|
{
|
|
room_up = value;
|
|
}
|
|
|
|
else if (var == "room_down")
|
|
{
|
|
room_down = value;
|
|
}
|
|
|
|
else if (var == "room_left")
|
|
{
|
|
room_left = value;
|
|
}
|
|
|
|
else if (var == "room_right")
|
|
{
|
|
room_right = value;
|
|
}
|
|
|
|
else if (var == "enemy_file")
|
|
{
|
|
enemy_file = value;
|
|
}
|
|
|
|
else if (var == "")
|
|
{
|
|
}
|
|
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Asigna variables a una estructura enemy_t
|
|
bool Map::setActor(actor_t *actor, SDL_Point *p1, SDL_Point *p2, std::string var, std::string value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (var == "tileset")
|
|
{
|
|
actor->tileset = value;
|
|
}
|
|
|
|
else if (var == "animation")
|
|
{
|
|
actor->animation = value;
|
|
}
|
|
|
|
else if (var == "width")
|
|
{
|
|
actor->w = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "height")
|
|
{
|
|
actor->h = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "x")
|
|
{
|
|
actor->x = std::stof(value) * tile_size;
|
|
}
|
|
|
|
else if (var == "y")
|
|
{
|
|
actor->y = std::stof(value) * tile_size;
|
|
}
|
|
|
|
else if (var == "vx")
|
|
{
|
|
actor->vx = std::stof(value);
|
|
}
|
|
|
|
else if (var == "vy")
|
|
{
|
|
actor->vy = std::stof(value);
|
|
}
|
|
|
|
else if (var == "x1")
|
|
{
|
|
p1->x = std::stoi(value) * tile_size;
|
|
}
|
|
|
|
else if (var == "x2")
|
|
{
|
|
p2->x = std::stoi(value) * tile_size;
|
|
}
|
|
|
|
else if (var == "y1")
|
|
{
|
|
p1->y = std::stoi(value) * tile_size;
|
|
}
|
|
|
|
else if (var == "y2")
|
|
{
|
|
p2->y = std::stoi(value) * tile_size;
|
|
}
|
|
|
|
else if ((var == "[/moving platform]") || (var == "[/diamond]"))
|
|
{
|
|
}
|
|
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Crea la textura con el mapeado de la habitación
|
|
void Map::fillMapTexture()
|
|
{
|
|
// Crea variables
|
|
SDL_Rect clip = {0, 0, tile_size, tile_size};
|
|
|
|
// Rellena la capa 0
|
|
{
|
|
SDL_SetRenderTarget(renderer, map_layer0);
|
|
SDL_SetTextureBlendMode(map_layer0, SDL_BLENDMODE_BLEND);
|
|
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
|
|
SDL_RenderClear(renderer);
|
|
|
|
// Dibuja el degradado de fondo
|
|
const float num_lines = PLAY_AREA_BOTTOM - PLAY_AREA_TOP;
|
|
|
|
for (int i = PLAY_AREA_TOP; i < PLAY_AREA_BOTTOM; i++)
|
|
{
|
|
float step = ((float)i / num_lines);
|
|
int r = bgColor1.r + ((bgColor2.r - bgColor1.r) * step);
|
|
int g = bgColor1.g + ((bgColor2.g - bgColor1.g) * step);
|
|
int b = bgColor1.b + ((bgColor2.b - bgColor1.b) * step);
|
|
SDL_SetRenderDrawColor(renderer, r, g, b, 0xFF);
|
|
SDL_RenderDrawLine(renderer, 0, i, 319, i);
|
|
}
|
|
|
|
// Dibuja el mapeado de tiles
|
|
for (int y = 0; y < map_height; y++)
|
|
for (int x = 0; x < map_width; x++)
|
|
{
|
|
// Resta uno porque Tiled almacena los indices empezando de 1 en vez de 0.
|
|
// El problema es que los tiles vacios los pone como 0 y aqui pasan a ser -1
|
|
// con lo que esta pintando desde fuera de la textura
|
|
clip.x = ((tilemap_l0[(y * map_width) + x] - 1) % tileset_width) * tile_size;
|
|
clip.y = ((tilemap_l0[(y * map_width) + x] - 1) / tileset_width) * tile_size;
|
|
texture_tile->render(renderer, x * tile_size, y * tile_size, &clip);
|
|
}
|
|
}
|
|
|
|
// Rellena la capa 1
|
|
{
|
|
SDL_SetRenderTarget(renderer, map_layer1);
|
|
SDL_SetTextureBlendMode(map_layer1, SDL_BLENDMODE_BLEND);
|
|
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
|
|
SDL_RenderClear(renderer);
|
|
|
|
// Dibuja el mapeado de tiles
|
|
for (int y = 0; y < map_height; y++)
|
|
for (int x = 0; x < map_width; x++)
|
|
{
|
|
// Resta uno porque Tiled almacena los indices empezando de 1 en vez de 0.
|
|
// El problema es que los tiles vacios los pone como 0 y aqui pasan a ser -1
|
|
// con lo que esta pintando desde fuera de la textura
|
|
clip.x = ((tilemap_l1[(y * map_width) + x] - 1) % tileset_width) * tile_size;
|
|
clip.y = ((tilemap_l1[(y * map_width) + x] - 1) / tileset_width) * tile_size;
|
|
texture_tile->render(renderer, x * tile_size, y * tile_size, &clip);
|
|
}
|
|
}
|
|
|
|
// Vuelve a colocar el renderizador
|
|
SDL_SetRenderTarget(renderer, nullptr);
|
|
}
|
|
|
|
// Dibuja todos los elementos del mapa
|
|
void Map::render()
|
|
{
|
|
renderLayer0();
|
|
renderLayer1();
|
|
renderActors();
|
|
}
|
|
|
|
// Dibuja la capa 0
|
|
void Map::renderLayer0()
|
|
{
|
|
// Dibuja la textura con el mapa en pantalla
|
|
if (bgScroll)
|
|
{
|
|
const int offset = PLAY_AREA_WIDTH - ((counter / 20) % PLAY_AREA_WIDTH);
|
|
SDL_Rect src1 = {PLAY_AREA_X, PLAY_AREA_Y, offset, PLAY_AREA_HEIGHT};
|
|
SDL_Rect dst1 = {PLAY_AREA_X + PLAY_AREA_WIDTH - offset, PLAY_AREA_Y, offset, PLAY_AREA_HEIGHT};
|
|
|
|
SDL_Rect src2 = {PLAY_AREA_X + offset, PLAY_AREA_Y, PLAY_AREA_WIDTH - offset, PLAY_AREA_HEIGHT};
|
|
SDL_Rect dst2 = {PLAY_AREA_X, PLAY_AREA_Y, PLAY_AREA_WIDTH - offset, PLAY_AREA_HEIGHT};
|
|
|
|
SDL_RenderCopy(renderer, map_layer0, &src1, &dst1);
|
|
SDL_RenderCopy(renderer, map_layer0, &src2, &dst2);
|
|
}
|
|
else
|
|
{
|
|
SDL_Rect rect = {PLAY_AREA_X, PLAY_AREA_Y, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT};
|
|
SDL_RenderCopy(renderer, map_layer0, nullptr, nullptr);
|
|
}
|
|
}
|
|
|
|
// Dibuja la capa 1
|
|
void Map::renderLayer1()
|
|
{
|
|
// Dibuja la textura con el mapa en pantalla
|
|
SDL_Rect rect = {PLAY_AREA_X, PLAY_AREA_Y, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT};
|
|
SDL_RenderCopy(renderer, map_layer1, NULL, &rect);
|
|
}
|
|
|
|
// Dibuja los actores
|
|
void Map::renderActors()
|
|
{
|
|
for (auto actor : actors)
|
|
{
|
|
actor->render();
|
|
}
|
|
}
|
|
|
|
// Actualiza todas las variables
|
|
void Map::update()
|
|
{
|
|
counter++;
|
|
|
|
for (auto actor : actors)
|
|
{
|
|
actor->update();
|
|
}
|
|
}
|
|
|
|
// Devuelve el tipo de tile que hay en un punto
|
|
e_tile_map Map::getTile(SDL_Point p)
|
|
{
|
|
// Normalizamos los puntos para que no busque fuera del mapa
|
|
const int x = std::max(getPlayArea(b_left), (std::min(p.x, getPlayArea(b_right) - 1)));
|
|
const int y = std::max(getPlayArea(b_top), (std::min(p.y, getPlayArea(b_bottom) - 1)));
|
|
|
|
// Calcula el tile
|
|
const int tile = collisionmap[((y / tile_size) * map_width) + (x / tile_size)];
|
|
|
|
if (tile == 0)
|
|
{
|
|
return nothing;
|
|
}
|
|
|
|
else if (tile == 5627)
|
|
{
|
|
return wall;
|
|
}
|
|
|
|
else if (tile == 5628)
|
|
{
|
|
return passable;
|
|
}
|
|
|
|
return nothing;
|
|
}
|
|
|
|
// Devuelve el valor de la variable
|
|
int Map::getTileSize()
|
|
{
|
|
return tile_size;
|
|
}
|
|
|
|
// Devuelve el valor de los bordes de la zona de juego
|
|
int Map::getPlayArea(e_border border)
|
|
{
|
|
switch (border)
|
|
{
|
|
case b_top:
|
|
return 0;
|
|
break;
|
|
|
|
case b_left:
|
|
return 0;
|
|
break;
|
|
|
|
case b_right:
|
|
return tile_size * map_width;
|
|
break;
|
|
|
|
case b_bottom:
|
|
return tile_size * map_height;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Devuelve el nombre del fichero de la habitación en funcion del borde
|
|
std::string Map::getRoomFileName(e_border border)
|
|
{
|
|
switch (border)
|
|
{
|
|
case b_top:
|
|
return room_up;
|
|
break;
|
|
|
|
case b_left:
|
|
return room_left;
|
|
break;
|
|
|
|
case b_right:
|
|
return room_right;
|
|
break;
|
|
|
|
case b_bottom:
|
|
return room_down;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
// Devuelve el nombre del fichero de la habitación
|
|
std::string Map::getName()
|
|
{
|
|
return name;
|
|
}
|
|
|
|
// Indica si hay colision con un actor a partir de un rectangulo
|
|
int Map::actorCollision(SDL_Rect &rect)
|
|
{
|
|
int index = 0;
|
|
for (auto actor : actors)
|
|
{
|
|
if (checkCollision(rect, actor->getCollider()))
|
|
{
|
|
return index;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Indica si hay colision con un actor a partir de un rectangulo
|
|
int Map::actorCollision(SDL_Point &p)
|
|
{
|
|
int index = 0;
|
|
for (auto actor : actors)
|
|
{
|
|
if (checkCollision(p, actor->getCollider()))
|
|
{
|
|
return index;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Devuelve el nombre del actor a pàrtir de un índice
|
|
int Map::getActorName(int index)
|
|
{
|
|
if (index != -1)
|
|
{
|
|
return actors[index]->getName();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Devuelve el rectangulo de colisión
|
|
SDL_Rect Map::getActorCollider(int index)
|
|
{
|
|
SDL_Rect rect = {0, 0, 0, 0};
|
|
if (index != -1)
|
|
{
|
|
rect = actors[index]->getCollider();
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
// Devuelve el desplazamiento relativo del actor
|
|
int Map::getActorIncX(int index)
|
|
{
|
|
int shift = 0;
|
|
if (index != -1)
|
|
{
|
|
shift = actors[index]->getIncX();
|
|
}
|
|
|
|
return shift;
|
|
}
|
|
|
|
// Elimina un actor
|
|
bool Map::deleteActor(int index)
|
|
{
|
|
bool success = false;
|
|
if (actors[index] != nullptr)
|
|
{
|
|
delete actors[index];
|
|
success = true;
|
|
}
|
|
|
|
actors.erase(actors.begin() + index);
|
|
return success;
|
|
}
|
|
|
|
// Coge un item
|
|
void Map::getItem(int index)
|
|
{
|
|
const SDL_Rect r = getActorCollider(index);
|
|
itemTracker->addItem(name, {r.x, r.y});
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
std::string Map::getEnemyFile()
|
|
{
|
|
return enemy_file;
|
|
}
|
|
|
|
// Recarga las texturas
|
|
void Map::reLoadTextures()
|
|
{
|
|
texture_tile->reLoad();
|
|
fillMapTexture();
|
|
} |