518 lines
14 KiB
C++
518 lines
14 KiB
C++
#include "room.h"
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
// Constructor
|
|
Room::Room(std::string _file_path, SDL_Renderer *_renderer, Asset *_asset, Item_tracker *_item_tracker)
|
|
{
|
|
// Copia los punteros a objetos
|
|
asset = _asset;
|
|
renderer = _renderer;
|
|
item_tracker = _item_tracker;
|
|
|
|
// Crea los objetos
|
|
texture = new LTexture();
|
|
load(_file_path);
|
|
loadTextureFromFile(texture, asset->get(tileset), renderer);
|
|
|
|
// Crea la textura para el mapa de tiles de la habitación
|
|
map_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT);
|
|
if (map_texture == NULL)
|
|
printf("Error: map_texture could not be created!\nSDL Error: %s\n", SDL_GetError());
|
|
|
|
// Pinta el mapa de la habitación en la textura
|
|
fillMapTexture();
|
|
}
|
|
|
|
// Destructor
|
|
Room::~Room()
|
|
{
|
|
// Reclama la memoria utilizada por los objetos
|
|
texture->unload();
|
|
delete texture;
|
|
texture = nullptr;
|
|
|
|
SDL_DestroyTexture(map_texture);
|
|
map_texture = nullptr;
|
|
|
|
for (auto enemy : enemy_list)
|
|
{
|
|
delete enemy;
|
|
}
|
|
enemy_list.clear();
|
|
|
|
for (auto item : item_list)
|
|
{
|
|
delete item;
|
|
}
|
|
item_list.clear();
|
|
}
|
|
|
|
// Carga las variables desde un fichero
|
|
bool Room::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", filename.c_str());
|
|
while (std::getline(file, line))
|
|
{
|
|
// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
|
|
if (line == "[enemy]")
|
|
{
|
|
enemy_t enemy;
|
|
enemy.asset = asset;
|
|
enemy.renderer = renderer;
|
|
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
// Procesa las dos subcadenas
|
|
if (!setEnemy(&enemy, 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 != "[enemy-end]");
|
|
|
|
// Añade el enemigo al vector de enemigos
|
|
enemy_list.push_back(new Enemy(enemy));
|
|
}
|
|
|
|
// Si la linea contiene el texto [tilemap] se realiza el proceso de carga del fichero tmx
|
|
else if (line == "[tilemap]")
|
|
{
|
|
// printf("Loading tilemap...\n");
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
if (line.find(".tmx") != std::string::npos)
|
|
{
|
|
// printf("Reading file %s\n", asset->get(line).c_str());
|
|
std::ifstream file2(asset->get(line)); // Abre el fichero tmx
|
|
if (file2.good())
|
|
{
|
|
bool data_read = false;
|
|
while (std::getline(file2, line)) // Lee el fichero linea a linea
|
|
{
|
|
if (!data_read)
|
|
{ // Lee lineas hasta que encuentre donde empiezan los datos del mapa
|
|
int pos = 0;
|
|
do
|
|
{
|
|
std::getline(file2, line);
|
|
// printf("parsing: %s\n", line.c_str());
|
|
|
|
pos = line.find("data encoding");
|
|
// printf("pos: %i\n", pos);
|
|
|
|
} while (pos == std::string::npos);
|
|
|
|
do
|
|
{ // Se introducen los valores separados por comas en un vector
|
|
data_read = true;
|
|
std::getline(file2, line);
|
|
if (line != "</data>")
|
|
{
|
|
// printf("data: %s\n", line.c_str());
|
|
std::stringstream ss(line);
|
|
std::string tmp;
|
|
while (getline(ss, tmp, ','))
|
|
{
|
|
// printf("tile: %s\n", tmp.c_str());
|
|
tilemap.push_back(std::stoi(tmp));
|
|
}
|
|
}
|
|
} while (line != "</data>");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (line != "[tilemap-end]");
|
|
}
|
|
|
|
// Si la linea contiene el texto [item] se realiza el proceso de carga de un item
|
|
else if (line == "[item]")
|
|
{
|
|
item_t item;
|
|
item.asset = asset;
|
|
item.renderer = renderer;
|
|
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
// Procesa las dos subcadenas
|
|
if (!setItem(&item, 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 != "[item-end]");
|
|
|
|
// Añade el item al vector de items
|
|
const SDL_Point itemPos = {item.x, item.y};
|
|
if (!item_tracker->hasBeenPicked(name, itemPos))
|
|
{
|
|
item_list.push_back(new Item(item));
|
|
}
|
|
}
|
|
|
|
// 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", 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 Room::setVars(std::string _var, std::string _value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (_var == "name")
|
|
{
|
|
name = _value;
|
|
}
|
|
else if (_var == "bg_color")
|
|
{
|
|
bg_color = stringToColor(_value);
|
|
}
|
|
else if (_var == "tileset")
|
|
{
|
|
tileset = _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 == "tilemap")
|
|
{
|
|
// Se introducen los valores separados por comas en un vector
|
|
std::stringstream ss(_value);
|
|
std::string tmp;
|
|
while (getline(ss, tmp, ','))
|
|
{
|
|
tilemap.push_back(std::stoi(tmp));
|
|
}
|
|
}
|
|
else if (_var == "")
|
|
{
|
|
}
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Asigna variables a una estructura enemy_t
|
|
bool Room::setEnemy(enemy_t *enemy, std::string _var, std::string _value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (_var == "tileset")
|
|
{
|
|
enemy->tileset = _value;
|
|
}
|
|
else if (_var == "width")
|
|
{
|
|
enemy->w = std::stof(_value);
|
|
}
|
|
else if (_var == "height")
|
|
{
|
|
enemy->h = std::stof(_value);
|
|
}
|
|
else if (_var == "x")
|
|
{
|
|
enemy->x = std::stof(_value) * BLOCK;
|
|
}
|
|
else if (_var == "y")
|
|
{
|
|
enemy->y = std::stof(_value) * BLOCK;
|
|
}
|
|
else if (_var == "vx")
|
|
{
|
|
enemy->vx = std::stof(_value);
|
|
}
|
|
else if (_var == "vy")
|
|
{
|
|
enemy->vy = std::stof(_value);
|
|
}
|
|
else if (_var == "x1")
|
|
{
|
|
enemy->x1 = std::stoi(_value) * BLOCK;
|
|
}
|
|
else if (_var == "x2")
|
|
{
|
|
enemy->x2 = std::stoi(_value) * BLOCK;
|
|
}
|
|
else if (_var == "y1")
|
|
{
|
|
enemy->y1 = std::stoi(_value) * BLOCK;
|
|
}
|
|
else if (_var == "y2")
|
|
{
|
|
enemy->y2 = std::stoi(_value) * BLOCK;
|
|
}
|
|
else if (_var == "color")
|
|
{
|
|
enemy->color = stringToColor(_value);
|
|
}
|
|
else if (_var == "[enemy-end]")
|
|
{
|
|
}
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Asigna variables a una estructura item_t
|
|
bool Room::setItem(item_t *item, std::string _var, std::string _value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (_var == "tileset")
|
|
{
|
|
item->tileset = _value;
|
|
}
|
|
else if (_var == "x")
|
|
{
|
|
item->x = std::stof(_value) * BLOCK;
|
|
}
|
|
else if (_var == "y")
|
|
{
|
|
item->y = std::stof(_value) * BLOCK;
|
|
}
|
|
else if (_var == "tile")
|
|
{
|
|
item->tile = std::stof(_value);
|
|
}
|
|
else if (_var == "[item-end]")
|
|
{
|
|
}
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Devuelve el nombre de la habitación
|
|
std::string Room::getName()
|
|
{
|
|
return name;
|
|
}
|
|
|
|
// Devuelve el color de la habitación
|
|
color_t Room::getBGColor()
|
|
{
|
|
return bg_color;
|
|
}
|
|
|
|
// Crea la textura con el mapeado de la habitación
|
|
void Room::fillMapTexture()
|
|
{
|
|
SDL_SetRenderTarget(renderer, map_texture);
|
|
SDL_SetTextureBlendMode(map_texture, SDL_BLENDMODE_BLEND);
|
|
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
|
|
SDL_RenderClear(renderer);
|
|
|
|
// Los tilesets son de 20x20 tiles. El primer tile es el 1. Cuentan hacia la derecha y hacia abajo
|
|
|
|
// printf("Filling map\n");
|
|
SDL_Rect clip = {0, 0, 8, 8};
|
|
for (int y = 0; y < 16; y++)
|
|
for (int x = 0; x < 32; x++)
|
|
{
|
|
clip.x = ((tilemap[(y * 32) + x] - 1) % 20) * 8;
|
|
clip.y = ((tilemap[(y * 32) + x] - 1) / 20) * 8;
|
|
// printf("tilemap [%i] = %i | x = %i | y = %i\n", ((y * 32) + x), tilemap[(y * 32) + x], clip.x, clip.y);
|
|
texture->render(renderer, x * 8, y * 8, &clip);
|
|
}
|
|
|
|
SDL_SetRenderTarget(renderer, nullptr);
|
|
}
|
|
|
|
// Dibuja el mapa en pantalla
|
|
void Room::drawMap()
|
|
{
|
|
SDL_Rect rect = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};
|
|
|
|
// Dibuja la textura con el mapa en pantalla
|
|
SDL_RenderCopy(renderer, map_texture, &rect, NULL);
|
|
}
|
|
|
|
// Dibuja los enemigos en pantalla
|
|
void Room::drawEnemies()
|
|
{
|
|
for (auto enemy : enemy_list)
|
|
{
|
|
enemy->draw();
|
|
}
|
|
}
|
|
|
|
// Dibuja los objetos en pantalla
|
|
void Room::drawItems()
|
|
{
|
|
for (auto item : item_list)
|
|
{
|
|
item->draw();
|
|
}
|
|
}
|
|
|
|
// Actualiza las variables y objetos de la habitación
|
|
void Room::update()
|
|
{
|
|
for (auto enemy : enemy_list)
|
|
{
|
|
enemy->update();
|
|
}
|
|
|
|
for (auto item : item_list)
|
|
{
|
|
item->update();
|
|
}
|
|
}
|
|
|
|
// Devuelve la cadena del fichero de la habitación contigua segun el borde
|
|
std::string Room::getRoom(int border)
|
|
{
|
|
switch (border)
|
|
{
|
|
case BORDER_TOP:
|
|
return room_up;
|
|
break;
|
|
|
|
case BORDER_BOTTOM:
|
|
return room_down;
|
|
break;
|
|
|
|
case BORDER_RIGHT:
|
|
return room_right;
|
|
break;
|
|
|
|
case BORDER_LEFT:
|
|
return room_left;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
// Devuelve el tipo de tile que hay en ese pixel
|
|
int Room::getTile(SDL_Point point)
|
|
{
|
|
int pos = ((point.y / 8) * 32) + (point.x / 8);
|
|
int tile = TILE_EMPTY;
|
|
|
|
if (pos < 512)
|
|
{
|
|
// Los tiles entre el 1 y el 80 son solidos
|
|
if ((tilemap[pos] > 0) && (tilemap[pos] < 201))
|
|
{
|
|
return TILE_SOLID;
|
|
}
|
|
|
|
// Los tiles mayores de 80 son atravesables
|
|
if ((tilemap[pos] > 200) && (tilemap[pos] < 381))
|
|
{
|
|
return TILE_TRAVESSABLE;
|
|
}
|
|
|
|
// Los tiles mayores de 80 son atravesables
|
|
if ((tilemap[pos] > 380) && (tilemap[pos] < 400))
|
|
{
|
|
return TILE_KILL;
|
|
}
|
|
}
|
|
|
|
return tile;
|
|
}
|
|
|
|
// Indica si hay colision con un enemigo a partir de un rectangulo
|
|
bool Room::enemyCollision(SDL_Rect &rect)
|
|
{
|
|
bool collision = false;
|
|
|
|
for (auto enemy : enemy_list)
|
|
{
|
|
collision |= checkCollision(rect, enemy->getCollider());
|
|
}
|
|
|
|
return collision;
|
|
}
|
|
|
|
// Indica si hay colision con un objeto a partir de un rectangulo
|
|
bool Room::itemCollision(SDL_Rect &rect)
|
|
{
|
|
bool collision = false;
|
|
for (auto item : item_list)
|
|
{
|
|
if (checkCollision(rect, item->getCollider()))
|
|
{
|
|
item->pick();
|
|
item_tracker->addItem(name, item->getPos());
|
|
collision = true;
|
|
}
|
|
}
|
|
|
|
return collision;
|
|
} |