forked from jaildesigner-jailgames/jaildoctors_dilemma
linter
This commit is contained in:
20
CLAUDE.md
20
CLAUDE.md
@@ -55,6 +55,26 @@ cmake --build build --clean-first
|
|||||||
|
|
||||||
**Important:** The build directory is `/Users/sergio/Gitea/jaildoctors_dilemma/build` and the output executable is placed in the project root directory.
|
**Important:** The build directory is `/Users/sergio/Gitea/jaildoctors_dilemma/build` and the output executable is placed in the project root directory.
|
||||||
|
|
||||||
|
### Linter (clang-tidy)
|
||||||
|
|
||||||
|
**IMPORTANT:** Always run the linter on specific files, NOT on the entire project, to avoid long execution times and errors in unrelated files.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Analyze a specific file (RECOMMENDED)
|
||||||
|
tools/linter/run_clang-tidy.sh source/game/entities/player.cpp
|
||||||
|
|
||||||
|
# Analyze multiple specific files
|
||||||
|
tools/linter/run_clang-tidy.sh source/game/entities/player.cpp source/game/entities/enemy.cpp
|
||||||
|
|
||||||
|
# Apply fixes automatically to a specific file
|
||||||
|
tools/linter/run_clang-tidy.sh --fix source/game/entities/player.cpp
|
||||||
|
|
||||||
|
# Analyze entire project (SLOW, may have errors in defaults.hpp)
|
||||||
|
tools/linter/run_clang-tidy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Running the linter on the entire project can produce errors in files like `defaults.hpp` that are unrelated to your changes. Always target specific files you're working on.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. High-Level Architecture Overview
|
## 1. High-Level Architecture Overview
|
||||||
|
|||||||
@@ -14,41 +14,26 @@ inline void readBytes(const uint8_t*& buffer, void* dst, size_t size) {
|
|||||||
buffer += size;
|
buffer += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gif::decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out) {
|
// Inicializa el diccionario LZW con los valores iniciales
|
||||||
// Verifica que el code_length tenga un rango razonable.
|
inline void initializeDictionary(std::vector<DictionaryEntry>& dictionary, int code_length, int& dictionary_ind) {
|
||||||
if (code_length < 2 || code_length > 12) {
|
int size = 1 << code_length;
|
||||||
throw std::runtime_error("Invalid LZW code length");
|
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
|
||||||
int bit;
|
|
||||||
int prev = -1;
|
|
||||||
std::vector<DictionaryEntry> dictionary;
|
|
||||||
int dictionary_ind;
|
|
||||||
unsigned int mask = 0x01;
|
|
||||||
int reset_code_length = code_length;
|
|
||||||
int clear_code = 1 << code_length;
|
|
||||||
int stop_code = clear_code + 1;
|
|
||||||
int match_len = 0;
|
|
||||||
|
|
||||||
// Inicializamos el diccionario con el tamaño correspondiente.
|
|
||||||
dictionary.resize(1 << (code_length + 1));
|
dictionary.resize(1 << (code_length + 1));
|
||||||
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
|
for (dictionary_ind = 0; dictionary_ind < size; dictionary_ind++) {
|
||||||
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
||||||
dictionary[dictionary_ind].prev = -1;
|
dictionary[dictionary_ind].prev = -1;
|
||||||
dictionary[dictionary_ind].len = 1;
|
dictionary[dictionary_ind].len = 1;
|
||||||
}
|
}
|
||||||
dictionary_ind += 2; // Reservamos espacio para clear y stop codes
|
dictionary_ind += 2; // Reservamos espacio para clear y stop codes
|
||||||
|
}
|
||||||
|
|
||||||
// Bucle principal: procesar el stream comprimido.
|
// Lee los próximos bits del stream de entrada para formar un código
|
||||||
while (input_length > 0) {
|
inline int readNextCode(const uint8_t*& input, int& input_length, unsigned int& mask, int code_length) {
|
||||||
int code = 0;
|
int code = 0;
|
||||||
// Lee (code_length + 1) bits para formar el código.
|
for (int i = 0; i < (code_length + 1); i++) {
|
||||||
for (i = 0; i < (code_length + 1); i++) {
|
|
||||||
if (input_length <= 0) {
|
if (input_length <= 0) {
|
||||||
throw std::runtime_error("Unexpected end of input in decompress");
|
throw std::runtime_error("Unexpected end of input in decompress");
|
||||||
}
|
}
|
||||||
bit = ((*input & mask) != 0) ? 1 : 0;
|
int bit = ((*input & mask) != 0) ? 1 : 0;
|
||||||
mask <<= 1;
|
mask <<= 1;
|
||||||
if (mask == 0x100) {
|
if (mask == 0x100) {
|
||||||
mask = 0x01;
|
mask = 0x01;
|
||||||
@@ -57,20 +42,84 @@ void Gif::decompress(int code_length, const uint8_t* input, int input_length, ui
|
|||||||
}
|
}
|
||||||
code |= (bit << i);
|
code |= (bit << i);
|
||||||
}
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encuentra el primer byte de una cadena del diccionario
|
||||||
|
inline uint8_t findFirstByte(const std::vector<DictionaryEntry>& dictionary, int code) {
|
||||||
|
int ptr = code;
|
||||||
|
while (dictionary[ptr].prev != -1) {
|
||||||
|
ptr = dictionary[ptr].prev;
|
||||||
|
}
|
||||||
|
return dictionary[ptr].byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agrega una nueva entrada al diccionario
|
||||||
|
inline void addDictionaryEntry(std::vector<DictionaryEntry>& dictionary, int& dictionary_ind,
|
||||||
|
int& code_length, int prev, int code) {
|
||||||
|
uint8_t first_byte;
|
||||||
|
if (code == dictionary_ind) {
|
||||||
|
first_byte = findFirstByte(dictionary, prev);
|
||||||
|
} else {
|
||||||
|
first_byte = findFirstByte(dictionary, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
dictionary[dictionary_ind].byte = first_byte;
|
||||||
|
dictionary[dictionary_ind].prev = prev;
|
||||||
|
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
|
||||||
|
dictionary_ind++;
|
||||||
|
|
||||||
|
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
|
||||||
|
code_length++;
|
||||||
|
dictionary.resize(1 << (code_length + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escribe la cadena decodificada al buffer de salida
|
||||||
|
inline int writeDecodedString(const std::vector<DictionaryEntry>& dictionary, int code, uint8_t*& out) {
|
||||||
|
int cur_code = code;
|
||||||
|
int match_len = dictionary[cur_code].len;
|
||||||
|
while (cur_code != -1) {
|
||||||
|
out[dictionary[cur_code].len - 1] = dictionary[cur_code].byte;
|
||||||
|
if (dictionary[cur_code].prev == cur_code) {
|
||||||
|
std::cerr << "Internal error; self-reference detected." << std::endl;
|
||||||
|
throw std::runtime_error("Internal error in decompress: self-reference");
|
||||||
|
}
|
||||||
|
cur_code = dictionary[cur_code].prev;
|
||||||
|
}
|
||||||
|
out += match_len;
|
||||||
|
return match_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gif::decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out) {
|
||||||
|
// Verifica que el code_length tenga un rango razonable.
|
||||||
|
if (code_length < 2 || code_length > 12) {
|
||||||
|
throw std::runtime_error("Invalid LZW code length");
|
||||||
|
}
|
||||||
|
|
||||||
|
int prev = -1;
|
||||||
|
std::vector<DictionaryEntry> dictionary;
|
||||||
|
int dictionary_ind;
|
||||||
|
unsigned int mask = 0x01;
|
||||||
|
int reset_code_length = code_length;
|
||||||
|
int clear_code = 1 << code_length;
|
||||||
|
int stop_code = clear_code + 1;
|
||||||
|
|
||||||
|
// Inicializamos el diccionario con el tamaño correspondiente.
|
||||||
|
initializeDictionary(dictionary, code_length, dictionary_ind);
|
||||||
|
|
||||||
|
// Bucle principal: procesar el stream comprimido.
|
||||||
|
while (input_length > 0) {
|
||||||
|
int code = readNextCode(input, input_length, mask, code_length);
|
||||||
|
|
||||||
if (code == clear_code) {
|
if (code == clear_code) {
|
||||||
// Reinicia el diccionario.
|
// Reinicia el diccionario.
|
||||||
code_length = reset_code_length;
|
code_length = reset_code_length;
|
||||||
dictionary.resize(1 << (code_length + 1));
|
initializeDictionary(dictionary, code_length, dictionary_ind);
|
||||||
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
|
|
||||||
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
|
||||||
dictionary[dictionary_ind].prev = -1;
|
|
||||||
dictionary[dictionary_ind].len = 1;
|
|
||||||
}
|
|
||||||
dictionary_ind += 2;
|
|
||||||
prev = -1;
|
prev = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code == stop_code) {
|
if (code == stop_code) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -82,28 +131,7 @@ void Gif::decompress(int code_length, const uint8_t* input, int input_length, ui
|
|||||||
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int ptr;
|
addDictionaryEntry(dictionary, dictionary_ind, code_length, prev, code);
|
||||||
if (code == dictionary_ind) {
|
|
||||||
ptr = prev;
|
|
||||||
while (dictionary[ptr].prev != -1) {
|
|
||||||
ptr = dictionary[ptr].prev;
|
|
||||||
}
|
|
||||||
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
|
|
||||||
} else {
|
|
||||||
ptr = code;
|
|
||||||
while (dictionary[ptr].prev != -1) {
|
|
||||||
ptr = dictionary[ptr].prev;
|
|
||||||
}
|
|
||||||
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
|
|
||||||
}
|
|
||||||
dictionary[dictionary_ind].prev = prev;
|
|
||||||
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
|
|
||||||
dictionary_ind++;
|
|
||||||
|
|
||||||
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
|
|
||||||
code_length++;
|
|
||||||
dictionary.resize(1 << (code_length + 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = code;
|
prev = code;
|
||||||
@@ -115,18 +143,7 @@ void Gif::decompress(int code_length, const uint8_t* input, int input_length, ui
|
|||||||
throw std::runtime_error("LZW error: invalid code encountered");
|
throw std::runtime_error("LZW error: invalid code encountered");
|
||||||
}
|
}
|
||||||
|
|
||||||
int cur_code = code; // Variable temporal para recorrer la cadena.
|
writeDecodedString(dictionary, code, out);
|
||||||
match_len = dictionary[cur_code].len;
|
|
||||||
while (cur_code != -1) {
|
|
||||||
// Se asume que dictionary[curCode].len > 0.
|
|
||||||
out[dictionary[cur_code].len - 1] = dictionary[cur_code].byte;
|
|
||||||
if (dictionary[cur_code].prev == cur_code) {
|
|
||||||
std::cerr << "Internal error; self-reference detected." << std::endl;
|
|
||||||
throw std::runtime_error("Internal error in decompress: self-reference");
|
|
||||||
}
|
|
||||||
cur_code = dictionary[cur_code].prev;
|
|
||||||
}
|
|
||||||
out += match_len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class OpenGLShader : public ShaderBackend {
|
|||||||
|
|
||||||
void render() override;
|
void render() override;
|
||||||
void setTextureSize(float width, float height) override;
|
void setTextureSize(float width, float height) override;
|
||||||
void cleanup() override;
|
void cleanup() final;
|
||||||
bool isHardwareAccelerated() const override { return is_initialized_; }
|
bool isHardwareAccelerated() const override { return is_initialized_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -127,10 +127,9 @@ SurfaceData Surface::loadSurface(const std::string& file_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Crear un objeto Gif y llamar a la función loadGif
|
// Crear un objeto Gif y llamar a la función loadGif
|
||||||
GIF::Gif gif;
|
|
||||||
Uint16 w = 0;
|
Uint16 w = 0;
|
||||||
Uint16 h = 0;
|
Uint16 h = 0;
|
||||||
std::vector<Uint8> raw_pixels = gif.loadGif(buffer.data(), w, h);
|
std::vector<Uint8> raw_pixels = GIF::Gif::loadGif(buffer.data(), w, h);
|
||||||
if (raw_pixels.empty()) {
|
if (raw_pixels.empty()) {
|
||||||
std::cerr << "Error loading GIF from file: " << file_path << std::endl;
|
std::cerr << "Error loading GIF from file: " << file_path << std::endl;
|
||||||
throw std::runtime_error("Error loading GIF");
|
throw std::runtime_error("Error loading GIF");
|
||||||
@@ -336,6 +335,24 @@ void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper para calcular coordenadas con flip
|
||||||
|
void Surface::calculateFlippedCoords(int ix, int iy, float sx, float sy, float w, float h, SDL_FlipMode flip, int& src_x, int& src_y) {
|
||||||
|
src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
|
||||||
|
src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper para copiar un pixel si no es transparente
|
||||||
|
void Surface::copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const {
|
||||||
|
if (dest_x < 0 || dest_y < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
||||||
|
if (color != transparent_color_) {
|
||||||
|
dest_data[dest_x + (dest_y * dest_width)] = sub_palette_[color];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Copia una región de la superficie de origen a la de destino
|
// Copia una región de la superficie de origen a la de destino
|
||||||
void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip) {
|
void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip) {
|
||||||
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
||||||
@@ -370,19 +387,16 @@ void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip
|
|||||||
// Renderiza píxel por píxel aplicando el flip si es necesario
|
// Renderiza píxel por píxel aplicando el flip si es necesario
|
||||||
for (int iy = 0; iy < final_height; ++iy) {
|
for (int iy = 0; iy < final_height; ++iy) {
|
||||||
for (int ix = 0; ix < final_width; ++ix) {
|
for (int ix = 0; ix < final_width; ++ix) {
|
||||||
// Coordenadas de origen
|
int src_x = 0;
|
||||||
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + final_width - 1 - ix) : (sx + ix);
|
int src_y = 0;
|
||||||
int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + final_height - 1 - iy) : (sy + iy);
|
calculateFlippedCoords(ix, iy, sx, sy, final_width, final_height, flip, src_x, src_y);
|
||||||
|
|
||||||
// Coordenadas de destino
|
int dest_x = dx + ix;
|
||||||
if (int dest_x = dx + ix; dest_x >= 0 && dest_x < surface_data->width) {
|
int dest_y = dy + iy;
|
||||||
if (int dest_y = dy + iy; dest_y >= 0 && dest_y < surface_data->height) {
|
|
||||||
// Copiar el píxel si no es transparente
|
// Verificar límites de destino antes de copiar
|
||||||
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
if (dest_x >= 0 && dest_x < surface_data->width && dest_y >= 0 && dest_y < surface_data->height) {
|
||||||
if (color != transparent_color_) {
|
copyPixelIfNotTransparent(surface_data->data.get(), dest_x, dest_y, surface_data->width, src_x, src_y);
|
||||||
surface_data->data[dest_x + (dest_y * surface_data->width)] = sub_palette_[color];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class Surface {
|
|||||||
|
|
||||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino
|
// Copia una región de la SurfaceData de origen a la SurfaceData de destino
|
||||||
void render(float dx, float dy, float sx, float sy, float w, float h);
|
void render(float dx, float dy, float sx, float sy, float w, float h);
|
||||||
void render(int x, int y, SDL_FRect* clip = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
void render(int x, int y, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
||||||
void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
||||||
|
|
||||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
||||||
@@ -130,4 +130,11 @@ class Surface {
|
|||||||
|
|
||||||
// Inicializa la sub paleta
|
// Inicializa la sub paleta
|
||||||
static void initializeSubPalette(SubPalette& palette) { std::iota(palette.begin(), palette.end(), 0); }
|
static void initializeSubPalette(SubPalette& palette) { std::iota(palette.begin(), palette.end(), 0); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Helper para calcular coordenadas con flip
|
||||||
|
static void calculateFlippedCoords(int ix, int iy, float sx, float sy, float w, float h, SDL_FlipMode flip, int& src_x, int& src_y);
|
||||||
|
|
||||||
|
// Helper para copiar un pixel si no es transparente
|
||||||
|
void copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -135,6 +135,96 @@ void SurfaceAnimatedSprite::resetAnimation() {
|
|||||||
animations_[current_animation_].completed = false;
|
animations_[current_animation_].completed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper: Parsea los parámetros de configuración globales (frame_width, frame_height)
|
||||||
|
bool parseGlobalParameter(const std::string& line, float& frame_width, float& frame_height) {
|
||||||
|
size_t pos = line.find("=");
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key = line.substr(0, pos);
|
||||||
|
int value = std::stoi(line.substr(pos + 1));
|
||||||
|
|
||||||
|
if (key == "frame_width") {
|
||||||
|
frame_width = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key == "frame_height") {
|
||||||
|
frame_height = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Warning: unknown parameter " << key << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: Parsea los frames de una animación desde una cadena separada por comas
|
||||||
|
void parseAnimationFrames(const std::string& value, AnimationData& animation,
|
||||||
|
float frame_width, float frame_height,
|
||||||
|
int frames_per_row, int max_tiles) {
|
||||||
|
std::stringstream ss(value);
|
||||||
|
std::string tmp;
|
||||||
|
SDL_FRect rect = {0.0F, 0.0F, frame_width, frame_height};
|
||||||
|
|
||||||
|
while (getline(ss, tmp, ',')) {
|
||||||
|
const int NUM_TILE = std::stoi(tmp);
|
||||||
|
if (NUM_TILE <= max_tiles) {
|
||||||
|
rect.x = (NUM_TILE % frames_per_row) * frame_width;
|
||||||
|
rect.y = (NUM_TILE / frames_per_row) * frame_height;
|
||||||
|
animation.frames.emplace_back(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: Parsea un parámetro de animación individual
|
||||||
|
bool parseAnimationParameter(const std::string& key, const std::string& value,
|
||||||
|
AnimationData& animation,
|
||||||
|
float frame_width, float frame_height,
|
||||||
|
int frames_per_row, int max_tiles) {
|
||||||
|
if (key == "name") {
|
||||||
|
animation.name = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key == "speed") {
|
||||||
|
animation.speed = std::stoi(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key == "loop") {
|
||||||
|
animation.loop = std::stoi(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (key == "frames") {
|
||||||
|
parseAnimationFrames(value, animation, frame_width, frame_height, frames_per_row, max_tiles);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Warning: unknown parameter " << key << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: Parsea una animación completa
|
||||||
|
AnimationData parseAnimation(const Animations& animations, size_t& index,
|
||||||
|
float frame_width, float frame_height,
|
||||||
|
int frames_per_row, int max_tiles) {
|
||||||
|
AnimationData animation;
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
do {
|
||||||
|
index++;
|
||||||
|
line = animations.at(index);
|
||||||
|
size_t pos = line.find("=");
|
||||||
|
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
std::string key = line.substr(0, pos);
|
||||||
|
std::string value = line.substr(pos + 1);
|
||||||
|
parseAnimationParameter(key, value, animation, frame_width, frame_height,
|
||||||
|
frames_per_row, max_tiles);
|
||||||
|
}
|
||||||
|
} while (line != "[/animation]");
|
||||||
|
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
|
||||||
// Carga la animación desde un vector de cadenas
|
// Carga la animación desde un vector de cadenas
|
||||||
void SurfaceAnimatedSprite::setAnimations(const Animations& animations) {
|
void SurfaceAnimatedSprite::setAnimations(const Animations& animations) {
|
||||||
float frame_width = 1.0F;
|
float frame_width = 1.0F;
|
||||||
@@ -148,21 +238,7 @@ void SurfaceAnimatedSprite::setAnimations(const Animations& animations) {
|
|||||||
|
|
||||||
// Parsea el fichero para buscar variables y valores
|
// Parsea el fichero para buscar variables y valores
|
||||||
if (line != "[animation]") {
|
if (line != "[animation]") {
|
||||||
// Encuentra la posición del caracter '='
|
if (parseGlobalParameter(line, frame_width, frame_height)) {
|
||||||
size_t pos = line.find("=");
|
|
||||||
|
|
||||||
// Procesa las dos subcadenas
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
std::string key = line.substr(0, pos);
|
|
||||||
int value = std::stoi(line.substr(pos + 1));
|
|
||||||
if (key == "frame_width") {
|
|
||||||
frame_width = value;
|
|
||||||
} else if (key == "frame_height") {
|
|
||||||
frame_height = value;
|
|
||||||
} else {
|
|
||||||
std::cout << "Warning: unknown parameter " << key << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
frames_per_row = surface_->getWidth() / frame_width;
|
frames_per_row = surface_->getWidth() / frame_width;
|
||||||
const int W = surface_->getWidth() / frame_width;
|
const int W = surface_->getWidth() / frame_width;
|
||||||
const int H = surface_->getHeight() / frame_height;
|
const int H = surface_->getHeight() / frame_height;
|
||||||
@@ -172,45 +248,8 @@ void SurfaceAnimatedSprite::setAnimations(const Animations& animations) {
|
|||||||
|
|
||||||
// Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación
|
// Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación
|
||||||
if (line == "[animation]") {
|
if (line == "[animation]") {
|
||||||
AnimationData animation;
|
AnimationData animation = parseAnimation(animations, index, frame_width, frame_height,
|
||||||
do {
|
frames_per_row, max_tiles);
|
||||||
index++;
|
|
||||||
line = animations.at(index);
|
|
||||||
size_t pos = line.find("=");
|
|
||||||
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
std::string key = line.substr(0, pos);
|
|
||||||
std::string value = line.substr(pos + 1);
|
|
||||||
|
|
||||||
if (key == "name") {
|
|
||||||
animation.name = value;
|
|
||||||
} else if (key == "speed") {
|
|
||||||
animation.speed = std::stoi(value);
|
|
||||||
} else if (key == "loop") {
|
|
||||||
animation.loop = std::stoi(value);
|
|
||||||
} else if (key == "frames") {
|
|
||||||
// Se introducen los valores separados por comas en un vector
|
|
||||||
std::stringstream ss(value);
|
|
||||||
std::string tmp;
|
|
||||||
SDL_FRect rect = {0.0F, 0.0F, frame_width, frame_height};
|
|
||||||
while (getline(ss, tmp, ',')) {
|
|
||||||
// Comprueba que el tile no sea mayor que el maximo indice permitido
|
|
||||||
const int NUM_TILE = std::stoi(tmp);
|
|
||||||
if (NUM_TILE <= max_tiles) {
|
|
||||||
rect.x = (NUM_TILE % frames_per_row) * frame_width;
|
|
||||||
rect.y = (NUM_TILE / frames_per_row) * frame_height;
|
|
||||||
animation.frames.emplace_back(rect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
std::cout << "Warning: unknown parameter " << key << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (line != "[/animation]");
|
|
||||||
|
|
||||||
// Añade la animación al vector de animaciones
|
|
||||||
animations_.emplace_back(animation);
|
animations_.emplace_back(animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ Enemy::Enemy(const EnemyData& enemy)
|
|||||||
sprite_->setWidth(enemy.w);
|
sprite_->setWidth(enemy.w);
|
||||||
sprite_->setHeight(enemy.h);
|
sprite_->setHeight(enemy.h);
|
||||||
|
|
||||||
const SDL_FlipMode FLIP = (should_flip_ && enemy.vx < 0.0F) ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
|
const int FLIP = (should_flip_ && enemy.vx < 0.0F) ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
|
||||||
const SDL_FlipMode MIRROR = should_mirror_ ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE;
|
const int MIRROR = should_mirror_ ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE;
|
||||||
sprite_->setFlip(static_cast<SDL_FlipMode>(FLIP | MIRROR));
|
sprite_->setFlip(static_cast<SDL_FlipMode>(FLIP | MIRROR));
|
||||||
|
|
||||||
collider_ = getRect();
|
collider_ = getRect();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <algorithm> // Para max, min
|
#include <algorithm> // Para max, min
|
||||||
#include <cmath> // Para ceil, abs
|
#include <cmath> // Para ceil, abs
|
||||||
|
#include <ranges> // Para std::ranges::any_of
|
||||||
|
|
||||||
#include "core/input/input.hpp" // Para Input, InputAction
|
#include "core/input/input.hpp" // Para Input, InputAction
|
||||||
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
|
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
|
||||||
@@ -213,18 +214,8 @@ void Player::applyGravity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalcula la posición del jugador y su animación
|
// Maneja el movimiento horizontal hacia la izquierda
|
||||||
void Player::move() {
|
void Player::moveHorizontalLeft() {
|
||||||
last_position_ = {x_, y_}; // Guarda la posicion actual antes de modificarla
|
|
||||||
applyGravity(); // Aplica gravedad al jugador
|
|
||||||
checkState(); // Comprueba el estado del jugador
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
debug_color_ = static_cast<Uint8>(PaletteColor::GREEN);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Se mueve hacia la izquierda
|
|
||||||
if (vx_ < 0.0F) {
|
|
||||||
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
||||||
SDL_FRect proj;
|
SDL_FRect proj;
|
||||||
proj.x = static_cast<int>(x_ + vx_);
|
proj.x = static_cast<int>(x_ + vx_);
|
||||||
@@ -261,10 +252,10 @@ void Player::move() {
|
|||||||
if (isOnDownSlope() && state_ != PlayerState::JUMPING) {
|
if (isOnDownSlope() && state_ != PlayerState::JUMPING) {
|
||||||
y_ += 1;
|
y_ += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se mueve hacia la derecha
|
// Maneja el movimiento horizontal hacia la derecha
|
||||||
else if (vx_ > 0.0F) {
|
void Player::moveHorizontalRight() {
|
||||||
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
||||||
SDL_FRect proj;
|
SDL_FRect proj;
|
||||||
proj.x = x_ + WIDTH;
|
proj.x = x_ + WIDTH;
|
||||||
@@ -301,24 +292,10 @@ void Player::move() {
|
|||||||
if (isOnDownSlope() && state_ != PlayerState::JUMPING) {
|
if (isOnDownSlope() && state_ != PlayerState::JUMPING) {
|
||||||
y_ += 1;
|
y_ += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si ha salido del suelo, el jugador cae
|
// Maneja el movimiento vertical hacia arriba
|
||||||
if (state_ == PlayerState::STANDING && !isOnFloor()) {
|
void Player::moveVerticalUp() {
|
||||||
setState(PlayerState::FALLING);
|
|
||||||
|
|
||||||
// Deja de estar enganchado a la superficie automatica
|
|
||||||
auto_movement_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si ha salido de una superficie automatica, detiene el movimiento automatico
|
|
||||||
if (state_ == PlayerState::STANDING && isOnFloor() && !isOnAutoSurface()) {
|
|
||||||
// Deja de estar enganchado a la superficie automatica
|
|
||||||
auto_movement_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Se mueve hacia arriba
|
|
||||||
if (vy_ < 0.0F) {
|
|
||||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
||||||
SDL_FRect proj;
|
SDL_FRect proj;
|
||||||
proj.x = static_cast<int>(x_);
|
proj.x = static_cast<int>(x_);
|
||||||
@@ -342,10 +319,10 @@ void Player::move() {
|
|||||||
y_ = POS + 1;
|
y_ = POS + 1;
|
||||||
setState(PlayerState::FALLING);
|
setState(PlayerState::FALLING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se mueve hacia abajo
|
// Maneja el movimiento vertical hacia abajo
|
||||||
else if (vy_ > 0.0F) {
|
void Player::moveVerticalDown() {
|
||||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
||||||
SDL_FRect proj;
|
SDL_FRect proj;
|
||||||
proj.x = x_;
|
proj.x = x_;
|
||||||
@@ -396,6 +373,41 @@ void Player::move() {
|
|||||||
y_ += vy_;
|
y_ += vy_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalcula la posición del jugador y su animación
|
||||||
|
void Player::move() {
|
||||||
|
last_position_ = {x_, y_}; // Guarda la posicion actual antes de modificarla
|
||||||
|
applyGravity(); // Aplica gravedad al jugador
|
||||||
|
checkState(); // Comprueba el estado del jugador
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
debug_color_ = static_cast<Uint8>(PaletteColor::GREEN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Movimiento horizontal
|
||||||
|
if (vx_ < 0.0F) {
|
||||||
|
moveHorizontalLeft();
|
||||||
|
} else if (vx_ > 0.0F) {
|
||||||
|
moveHorizontalRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si ha salido del suelo, el jugador cae
|
||||||
|
if (state_ == PlayerState::STANDING && !isOnFloor()) {
|
||||||
|
setState(PlayerState::FALLING);
|
||||||
|
auto_movement_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si ha salido de una superficie automatica, detiene el movimiento automatico
|
||||||
|
if (state_ == PlayerState::STANDING && isOnFloor() && !isOnAutoSurface()) {
|
||||||
|
auto_movement_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Movimiento vertical
|
||||||
|
if (vy_ < 0.0F) {
|
||||||
|
moveVerticalUp();
|
||||||
|
} else if (vy_ > 0.0F) {
|
||||||
|
moveVerticalDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
placeSprite(); // Coloca el sprite en la nueva posición
|
placeSprite(); // Coloca el sprite en la nueva posición
|
||||||
@@ -534,13 +546,13 @@ bool Player::checkKillingTiles() {
|
|||||||
// Actualiza los puntos de colisión
|
// Actualiza los puntos de colisión
|
||||||
updateColliderPoints();
|
updateColliderPoints();
|
||||||
|
|
||||||
// Comprueba si hay contacto y retorna en cuanto se encuentra colisión
|
// Comprueba si hay contacto con algún tile que mata
|
||||||
for (const auto& c : collider_points_) {
|
if (std::ranges::any_of(collider_points_, [this](const auto& c) {
|
||||||
if (room_->getTile(c) == TileType::KILL) {
|
return room_->getTile(c) == TileType::KILL;
|
||||||
|
})) {
|
||||||
is_alive_ = false; // Mata al jugador inmediatamente
|
is_alive_ = false; // Mata al jugador inmediatamente
|
||||||
return true; // Retorna en cuanto se detecta una colisión
|
return true; // Retorna en cuanto se detecta una colisión
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false; // No se encontró ninguna colisión
|
return false; // No se encontró ninguna colisión
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,18 @@ class Player {
|
|||||||
// Recalcula la posición del jugador y su animación
|
// Recalcula la posición del jugador y su animación
|
||||||
void move();
|
void move();
|
||||||
|
|
||||||
|
// Maneja el movimiento horizontal hacia la izquierda
|
||||||
|
void moveHorizontalLeft();
|
||||||
|
|
||||||
|
// Maneja el movimiento horizontal hacia la derecha
|
||||||
|
void moveHorizontalRight();
|
||||||
|
|
||||||
|
// Maneja el movimiento vertical hacia arriba
|
||||||
|
void moveVerticalUp();
|
||||||
|
|
||||||
|
// Maneja el movimiento vertical hacia abajo
|
||||||
|
void moveVerticalDown();
|
||||||
|
|
||||||
// Establece la animación del jugador
|
// Establece la animación del jugador
|
||||||
void animate();
|
void animate();
|
||||||
|
|
||||||
@@ -163,7 +175,7 @@ class Player {
|
|||||||
void applySpawnValues(const PlayerSpawn& spawn);
|
void applySpawnValues(const PlayerSpawn& spawn);
|
||||||
|
|
||||||
// Inicializa el sprite del jugador
|
// Inicializa el sprite del jugador
|
||||||
void initSprite(const std::string& texture_path, const std::string& animations_path);
|
void initSprite(const std::string& surface_path, const std::string& animations_path);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Pinta la información de debug del jugador
|
// Pinta la información de debug del jugador
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "game/gameplay/room.hpp"
|
#include "game/gameplay/room.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // Para std::ranges::any_of
|
||||||
#include <exception> // Para exception
|
#include <exception> // Para exception
|
||||||
#include <fstream> // Para basic_ostream, operator<<, basic_istream
|
#include <fstream> // Para basic_ostream, operator<<, basic_istream
|
||||||
#include <iostream> // Para cout, cerr
|
#include <iostream> // Para cout, cerr
|
||||||
@@ -60,6 +61,61 @@ std::vector<int> loadRoomTileFile(const std::string& file_path, bool verbose) {
|
|||||||
return tile_map_file;
|
return tile_map_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parsea una línea en key y value separados por '='
|
||||||
|
std::pair<std::string, std::string> parseKeyValue(const std::string& line) {
|
||||||
|
int pos = line.find("=");
|
||||||
|
std::string key = line.substr(0, pos);
|
||||||
|
std::string value = line.substr(pos + 1, line.length());
|
||||||
|
return {key, value};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Muestra un warning de parámetro desconocido
|
||||||
|
void logUnknownParameter(const std::string& file_name, const std::string& key, bool verbose) {
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << key.c_str() << "\"" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga un bloque [enemy]...[/enemy] desde un archivo
|
||||||
|
EnemyData loadEnemyFromFile(std::ifstream& file, const std::string& file_name, bool verbose) {
|
||||||
|
EnemyData enemy;
|
||||||
|
enemy.flip = false;
|
||||||
|
enemy.mirror = false;
|
||||||
|
enemy.frame = -1;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
do {
|
||||||
|
std::getline(file, line);
|
||||||
|
auto [key, value] = parseKeyValue(line);
|
||||||
|
|
||||||
|
if (!setEnemy(&enemy, key, value)) {
|
||||||
|
logUnknownParameter(file_name, key, verbose);
|
||||||
|
}
|
||||||
|
} while (line != "[/enemy]");
|
||||||
|
|
||||||
|
return enemy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga un bloque [item]...[/item] desde un archivo
|
||||||
|
ItemData loadItemFromFile(std::ifstream& file, const std::string& file_name, bool verbose) {
|
||||||
|
ItemData item;
|
||||||
|
item.counter = 0;
|
||||||
|
item.color1 = stringToColor("yellow");
|
||||||
|
item.color2 = stringToColor("magenta");
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
do {
|
||||||
|
std::getline(file, line);
|
||||||
|
auto [key, value] = parseKeyValue(line);
|
||||||
|
|
||||||
|
if (!setItem(&item, key, value)) {
|
||||||
|
logUnknownParameter(file_name, key, verbose);
|
||||||
|
}
|
||||||
|
} while (line != "[/item]");
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
// Carga las variables desde un fichero de mapa
|
// Carga las variables desde un fichero de mapa
|
||||||
RoomData loadRoomFile(const std::string& file_path, bool verbose) {
|
RoomData loadRoomFile(const std::string& file_path, bool verbose) {
|
||||||
RoomData room;
|
RoomData room;
|
||||||
@@ -79,70 +135,17 @@ RoomData loadRoomFile(const std::string& file_path, bool verbose) {
|
|||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
|
// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
|
||||||
if (line == "[enemy]") {
|
if (line == "[enemy]") {
|
||||||
EnemyData enemy;
|
room.enemies.push_back(loadEnemyFromFile(file, FILE_NAME, verbose));
|
||||||
enemy.flip = false;
|
|
||||||
enemy.mirror = false;
|
|
||||||
enemy.frame = -1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
std::getline(file, line);
|
|
||||||
|
|
||||||
// Encuentra la posición del caracter '='
|
|
||||||
int pos = line.find("=");
|
|
||||||
|
|
||||||
// Procesa las dos subcadenas
|
|
||||||
std::string key = line.substr(0, pos);
|
|
||||||
std::string value = line.substr(pos + 1, line.length());
|
|
||||||
if (!setEnemy(&enemy, key, value)) {
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Warning: file " << FILE_NAME.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} while (line != "[/enemy]");
|
|
||||||
|
|
||||||
// Añade el enemigo al vector de enemigos
|
|
||||||
room.enemies.push_back(enemy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si la linea contiene el texto [item] se realiza el proceso de carga de un item
|
// Si la linea contiene el texto [item] se realiza el proceso de carga de un item
|
||||||
else if (line == "[item]") {
|
else if (line == "[item]") {
|
||||||
ItemData item;
|
room.items.push_back(loadItemFromFile(file, FILE_NAME, verbose));
|
||||||
item.counter = 0;
|
|
||||||
item.color1 = stringToColor("yellow");
|
|
||||||
item.color2 = stringToColor("magenta");
|
|
||||||
|
|
||||||
do {
|
|
||||||
std::getline(file, line);
|
|
||||||
|
|
||||||
// Encuentra la posición del caracter '='
|
|
||||||
int pos = line.find("=");
|
|
||||||
|
|
||||||
// Procesa las dos subcadenas
|
|
||||||
std::string key = line.substr(0, pos);
|
|
||||||
std::string value = line.substr(pos + 1, line.length());
|
|
||||||
if (!setItem(&item, key, value)) {
|
|
||||||
if (verbose) {
|
|
||||||
std::cout << "Warning: file " << FILE_NAME.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} while (line != "[/item]");
|
|
||||||
|
|
||||||
room.items.push_back(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// En caso contrario se parsea el fichero para buscar las variables y los valores
|
// En caso contrario se parsea el fichero para buscar las variables y los valores
|
||||||
else {
|
else {
|
||||||
// Encuentra la posición del caracter '='
|
auto [key, value] = parseKeyValue(line);
|
||||||
int pos = line.find("=");
|
|
||||||
|
|
||||||
// Procesa las dos subcadenas
|
|
||||||
std::string key = line.substr(0, pos);
|
|
||||||
std::string value = line.substr(pos + 1, line.length());
|
|
||||||
if (!setRoom(&room, key, value)) {
|
if (!setRoom(&room, key, value)) {
|
||||||
if (verbose) {
|
logUnknownParameter(FILE_NAME, key, verbose);
|
||||||
std::cout << "Warning: file " << FILE_NAME.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,10 +158,8 @@ RoomData loadRoomFile(const std::string& file_path, bool verbose) {
|
|||||||
}
|
}
|
||||||
// El fichero no se puede abrir
|
// El fichero no se puede abrir
|
||||||
else {
|
else {
|
||||||
{
|
|
||||||
std::cout << "Warning: Unable to open " << FILE_NAME.c_str() << " file" << std::endl;
|
std::cout << "Warning: Unable to open " << FILE_NAME.c_str() << " file" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
@@ -555,7 +556,7 @@ TileType Room::getTile(int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// La fila 23 es de tiles t_kill
|
// La fila 23 es de tiles t_kill
|
||||||
else if ((tile_map_[index] >= 23 * tile_set_width_) && (tile_map_[index] < 24 * tile_set_width_)) {
|
if ((tile_map_[index] >= 23 * tile_set_width_) && (tile_map_[index] < 24 * tile_set_width_)) {
|
||||||
return TileType::KILL;
|
return TileType::KILL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,12 +566,9 @@ TileType Room::getTile(int index) {
|
|||||||
|
|
||||||
// Indica si hay colision con un enemigo a partir de un rectangulo
|
// Indica si hay colision con un enemigo a partir de un rectangulo
|
||||||
bool Room::enemyCollision(SDL_FRect& rect) {
|
bool Room::enemyCollision(SDL_FRect& rect) {
|
||||||
for (const auto& enemy : enemies_) {
|
return std::ranges::any_of(enemies_, [&rect](const auto& enemy) {
|
||||||
if (checkCollision(rect, enemy->getCollider())) {
|
return checkCollision(rect, enemy->getCollider());
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indica si hay colision con un objeto a partir de un rectangulo
|
// Indica si hay colision con un objeto a partir de un rectangulo
|
||||||
@@ -619,8 +617,8 @@ int Room::getSlopeHeight(SDL_FPoint p, TileType slope) {
|
|||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcula las superficies inferiores
|
// Helper: recopila tiles inferiores (muros sin muro debajo)
|
||||||
void Room::setBottomSurfaces() {
|
std::vector<int> Room::collectBottomTiles() {
|
||||||
std::vector<int> tile;
|
std::vector<int> tile;
|
||||||
|
|
||||||
// Busca todos los tiles de tipo muro que no tengan debajo otro muro
|
// Busca todos los tiles de tipo muro que no tengan debajo otro muro
|
||||||
@@ -638,40 +636,11 @@ void Room::setBottomSurfaces() {
|
|||||||
|
|
||||||
// Añade un terminador
|
// Añade un terminador
|
||||||
tile.push_back(-1);
|
tile.push_back(-1);
|
||||||
|
return tile;
|
||||||
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
|
|
||||||
if ((int)tile.size() > 1) {
|
|
||||||
int i = 0;
|
|
||||||
do {
|
|
||||||
LineHorizontal line;
|
|
||||||
line.x1 = (tile[i] % MAP_WIDTH) * TILE_SIZE;
|
|
||||||
line.y = ((tile[i] / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
|
|
||||||
int last_one = i;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i <= (int)tile.size() - 1) {
|
|
||||||
while (tile[i] == tile[i - 1] + 1) {
|
|
||||||
last_one = i;
|
|
||||||
if (i == (int)tile.size() - 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line.x2 = ((tile[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
|
|
||||||
bottom_floors_.push_back(line);
|
|
||||||
if (i <= (int)tile.size() - 1) {
|
|
||||||
if (tile[i] == -1) { // Si el siguiente elemento es un separador, hay que saltarlo
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (i < (int)tile.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcula las superficies superiores
|
// Helper: recopila tiles superiores (muros o pasables sin muro encima)
|
||||||
void Room::setTopSurfaces() {
|
std::vector<int> Room::collectTopTiles() {
|
||||||
std::vector<int> tile;
|
std::vector<int> tile;
|
||||||
|
|
||||||
// Busca todos los tiles de tipo muro o pasable que no tengan encima un muro
|
// Busca todos los tiles de tipo muro o pasable que no tengan encima un muro
|
||||||
@@ -689,36 +658,61 @@ void Room::setTopSurfaces() {
|
|||||||
|
|
||||||
// Añade un terminador
|
// Añade un terminador
|
||||||
tile.push_back(-1);
|
tile.push_back(-1);
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: construye lineas horizontales a partir de tiles consecutivos
|
||||||
|
void Room::buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface) {
|
||||||
|
if (tiles.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
|
|
||||||
if ((int)tile.size() > 1) {
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
do {
|
while (i < (int)tiles.size() - 1) {
|
||||||
LineHorizontal line;
|
LineHorizontal line;
|
||||||
line.x1 = (tile[i] % MAP_WIDTH) * TILE_SIZE;
|
line.x1 = (tiles[i] % MAP_WIDTH) * TILE_SIZE;
|
||||||
line.y = (tile[i] / MAP_WIDTH) * TILE_SIZE;
|
|
||||||
|
// Calcula Y segun si es superficie inferior o superior
|
||||||
|
if (is_bottom_surface) {
|
||||||
|
line.y = ((tiles[i] / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
|
||||||
|
} else {
|
||||||
|
line.y = (tiles[i] / MAP_WIDTH) * TILE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
int last_one = i;
|
int last_one = i;
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (i <= (int)tile.size() - 1) {
|
// Encuentra tiles consecutivos
|
||||||
while (tile[i] == tile[i - 1] + 1) {
|
if (i < (int)tiles.size()) {
|
||||||
|
while (tiles[i] == tiles[i - 1] + 1) {
|
||||||
last_one = i;
|
last_one = i;
|
||||||
if (i == (int)tile.size() - 1) {
|
i++;
|
||||||
|
if (i >= (int)tiles.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
line.x2 = ((tile[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
|
line.x2 = ((tiles[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
|
||||||
top_floors_.push_back(line);
|
lines.push_back(line);
|
||||||
if (i <= (int)tile.size() - 1) {
|
|
||||||
if (tile[i] == -1) { // Si el siguiente elemento es un separador, hay que saltarlo
|
// Salta separadores
|
||||||
|
if (i < (int)tiles.size() && tiles[i] == -1) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (i < (int)tile.size() - 1);
|
}
|
||||||
}
|
|
||||||
|
// Calcula las superficies inferiores
|
||||||
|
void Room::setBottomSurfaces() {
|
||||||
|
std::vector<int> tile = collectBottomTiles();
|
||||||
|
buildHorizontalLines(tile, bottom_floors_, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcula las superficies superiores
|
||||||
|
void Room::setTopSurfaces() {
|
||||||
|
std::vector<int> tile = collectTopTiles();
|
||||||
|
buildHorizontalLines(tile, top_floors_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcula las superficies laterales izquierdas
|
// Calcula las superficies laterales izquierdas
|
||||||
@@ -872,7 +866,8 @@ void Room::setRightSlopes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calcula las superficies automaticas
|
// Calcula las superficies automaticas
|
||||||
void Room::setAutoSurfaces() {
|
// Helper: recopila tiles animados (para superficies automaticas/conveyor belts)
|
||||||
|
std::vector<int> Room::collectAnimatedTiles() {
|
||||||
std::vector<int> tile;
|
std::vector<int> tile;
|
||||||
|
|
||||||
// Busca todos los tiles de tipo animado
|
// Busca todos los tiles de tipo animado
|
||||||
@@ -888,35 +883,17 @@ void Room::setAutoSurfaces() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
|
// Añade un terminador si hay tiles
|
||||||
if ((int)tile.size() > 0) {
|
if (!tile.empty()) {
|
||||||
int i = 0;
|
tile.push_back(-1);
|
||||||
do {
|
|
||||||
LineHorizontal line;
|
|
||||||
line.x1 = (tile[i] % MAP_WIDTH) * TILE_SIZE;
|
|
||||||
line.y = (tile[i] / MAP_WIDTH) * TILE_SIZE;
|
|
||||||
int last_one = i;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i <= (int)tile.size() - 1) {
|
|
||||||
while (tile[i] == tile[i - 1] + 1) {
|
|
||||||
last_one = i;
|
|
||||||
if (i == (int)tile.size() - 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
line.x2 = ((tile[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
|
return tile;
|
||||||
conveyor_belt_floors_.push_back(line);
|
}
|
||||||
if (i <= (int)tile.size() - 1) {
|
|
||||||
if (tile[i] == -1) { // Si el siguiente elemento es un separador, hay que saltarlo
|
void Room::setAutoSurfaces() {
|
||||||
i++;
|
std::vector<int> tile = collectAnimatedTiles();
|
||||||
}
|
buildHorizontalLines(tile, conveyor_belt_floors_, false);
|
||||||
}
|
|
||||||
} while (i < (int)tile.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Localiza todos los tiles animados de la habitación
|
// Localiza todos los tiles animados de la habitación
|
||||||
@@ -1022,24 +999,16 @@ int Room::checkAutoSurfaces(SDL_FRect* rect) {
|
|||||||
|
|
||||||
// Comprueba las colisiones
|
// Comprueba las colisiones
|
||||||
bool Room::checkTopSurfaces(SDL_FPoint* p) {
|
bool Room::checkTopSurfaces(SDL_FPoint* p) {
|
||||||
for (const auto& s : top_floors_) {
|
return std::ranges::any_of(top_floors_, [&](const auto& s) {
|
||||||
if (checkCollision(s, *p)) {
|
return checkCollision(s, *p);
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba las colisiones
|
// Comprueba las colisiones
|
||||||
bool Room::checkAutoSurfaces(SDL_FPoint* p) {
|
bool Room::checkAutoSurfaces(SDL_FPoint* p) {
|
||||||
for (const auto& s : conveyor_belt_floors_) {
|
return std::ranges::any_of(conveyor_belt_floors_, [&](const auto& s) {
|
||||||
if (checkCollision(s, *p)) {
|
return checkCollision(s, *p);
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba las colisiones
|
// Comprueba las colisiones
|
||||||
@@ -1056,13 +1025,9 @@ int Room::checkLeftSlopes(const LineVertical* line) {
|
|||||||
|
|
||||||
// Comprueba las colisiones
|
// Comprueba las colisiones
|
||||||
bool Room::checkLeftSlopes(SDL_FPoint* p) {
|
bool Room::checkLeftSlopes(SDL_FPoint* p) {
|
||||||
for (const auto& slope : left_slopes_) {
|
return std::ranges::any_of(left_slopes_, [&](const auto& slope) {
|
||||||
if (checkCollision(*p, slope)) {
|
return checkCollision(*p, slope);
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba las colisiones
|
// Comprueba las colisiones
|
||||||
@@ -1079,13 +1044,9 @@ int Room::checkRightSlopes(const LineVertical* line) {
|
|||||||
|
|
||||||
// Comprueba las colisiones
|
// Comprueba las colisiones
|
||||||
bool Room::checkRightSlopes(SDL_FPoint* p) {
|
bool Room::checkRightSlopes(SDL_FPoint* p) {
|
||||||
for (const auto& slope : right_slopes_) {
|
return std::ranges::any_of(right_slopes_, [&](const auto& slope) {
|
||||||
if (checkCollision(*p, slope)) {
|
return checkCollision(*p, slope);
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abre la Jail si se da el caso
|
// Abre la Jail si se da el caso
|
||||||
|
|||||||
@@ -115,6 +115,18 @@ class Room {
|
|||||||
// Pinta el mapa de la habitación en la textura
|
// Pinta el mapa de la habitación en la textura
|
||||||
void fillMapTexture();
|
void fillMapTexture();
|
||||||
|
|
||||||
|
// Helper para recopilar tiles inferiores
|
||||||
|
std::vector<int> collectBottomTiles();
|
||||||
|
|
||||||
|
// Helper para recopilar tiles superiores
|
||||||
|
std::vector<int> collectTopTiles();
|
||||||
|
|
||||||
|
// Helper para recopilar tiles animados (para superficies automaticas)
|
||||||
|
std::vector<int> collectAnimatedTiles();
|
||||||
|
|
||||||
|
// Helper para construir lineas horizontales a partir de tiles consecutivos
|
||||||
|
static void buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface);
|
||||||
|
|
||||||
// Calcula las superficies inferiores
|
// Calcula las superficies inferiores
|
||||||
void setBottomSurfaces();
|
void setBottomSurfaces();
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
#include "game/gameplay/room_tracker.hpp"
|
#include "game/gameplay/room_tracker.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // Para std::ranges::any_of
|
||||||
|
|
||||||
// Comprueba si la habitación ya ha sido visitada
|
// Comprueba si la habitación ya ha sido visitada
|
||||||
bool RoomTracker::hasBeenVisited(const std::string& name) {
|
bool RoomTracker::hasBeenVisited(const std::string& name) {
|
||||||
for (const auto& l : list_) {
|
return std::ranges::any_of(list_, [&name](const auto& l) { return l == name; });
|
||||||
if (l == name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Añade la habitación a la lista
|
// Añade la habitación a la lista
|
||||||
|
|||||||
@@ -15,8 +15,12 @@
|
|||||||
#include "utils/utils.hpp" // Para stringToBool, boolToString, safeStoi
|
#include "utils/utils.hpp" // Para stringToBool, boolToString, safeStoi
|
||||||
|
|
||||||
namespace Options {
|
namespace Options {
|
||||||
// Declaración de función interna
|
// Declaración de funciones internas
|
||||||
bool setOptions(const std::string& var, const std::string& value);
|
bool setOptions(const std::string& var, const std::string& value);
|
||||||
|
std::string trimLine(const std::string& line);
|
||||||
|
bool isCommentOrEmpty(const std::string& line);
|
||||||
|
bool processConfigLine(const std::string& line);
|
||||||
|
bool readConfigFile(const std::string& file_path);
|
||||||
|
|
||||||
// Crea e inicializa las opciones del programa
|
// Crea e inicializa las opciones del programa
|
||||||
void init() {
|
void init() {
|
||||||
@@ -27,39 +31,20 @@ void init() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carga las opciones desde un fichero
|
// Elimina espacios en blanco al inicio y final de una línea
|
||||||
bool loadFromFile(const std::string& file_path) {
|
std::string trimLine(const std::string& line) {
|
||||||
// Indicador de éxito en la carga
|
auto start = std::find_if(line.begin(), line.end(), [](int ch) { return !std::isspace(ch); });
|
||||||
bool success = true;
|
auto end = std::find_if(line.rbegin(), line.rend(), [](int ch) { return !std::isspace(ch); }).base();
|
||||||
|
return std::string(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
// Versión actual del fichero
|
// Verifica si una línea es comentario o está vacía
|
||||||
const std::string CONFIG_VERSION = version;
|
bool isCommentOrEmpty(const std::string& line) {
|
||||||
version = "";
|
return line.empty() || line[0] == '#';
|
||||||
|
}
|
||||||
|
|
||||||
// Variables para manejar el fichero
|
// Procesa una línea de configuración individual
|
||||||
std::ifstream file(file_path);
|
bool processConfigLine(const std::string& line) {
|
||||||
|
|
||||||
// Si el fichero se puede abrir
|
|
||||||
if (file.good()) {
|
|
||||||
// Procesa el fichero línea a línea
|
|
||||||
if (console) {
|
|
||||||
std::cout << "Reading file config.txt\n";
|
|
||||||
}
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(file, line)) {
|
|
||||||
// Elimina espacios en blanco iniciales y finales
|
|
||||||
line = std::string(std::find_if(line.begin(), line.end(), [](int ch) { return !std::isspace(ch); }),
|
|
||||||
line.end());
|
|
||||||
line.erase(std::find_if(line.rbegin(), line.rend(), [](int ch) { return !std::isspace(ch); })
|
|
||||||
.base(),
|
|
||||||
line.end());
|
|
||||||
|
|
||||||
// Ignora líneas vacías o comentarios
|
|
||||||
if (line.empty() || line[0] == '#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usa un stringstream para dividir la línea en dos partes
|
|
||||||
std::istringstream iss(line);
|
std::istringstream iss(line);
|
||||||
std::string key;
|
std::string key;
|
||||||
std::string value;
|
std::string value;
|
||||||
@@ -70,19 +55,58 @@ bool loadFromFile(const std::string& file_path) {
|
|||||||
std::cout << "Warning: file config.txt\n";
|
std::cout << "Warning: file config.txt\n";
|
||||||
std::cout << "unknown parameter " << key << std::endl;
|
std::cout << "unknown parameter " << key << std::endl;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lee y procesa el fichero de configuración
|
||||||
|
bool readConfigFile(const std::string& file_path) {
|
||||||
|
std::ifstream file(file_path);
|
||||||
|
if (!file.good()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
if (console) {
|
||||||
|
std::cout << "Reading file config.txt\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
line = trimLine(line);
|
||||||
|
|
||||||
|
if (isCommentOrEmpty(line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!processConfigLine(line)) {
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Cierra el fichero
|
|
||||||
if (console) {
|
if (console) {
|
||||||
std::cout << "Closing file config.txt\n\n";
|
std::cout << "Closing file config.txt\n\n";
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
} else {
|
|
||||||
// Crea el fichero con los valores por defecto
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga las opciones desde un fichero
|
||||||
|
bool loadFromFile(const std::string& file_path) {
|
||||||
|
// Versión actual del fichero
|
||||||
|
const std::string CONFIG_VERSION = version;
|
||||||
|
version = "";
|
||||||
|
|
||||||
|
// Intenta leer el fichero
|
||||||
|
bool success = readConfigFile(file_path);
|
||||||
|
|
||||||
|
// Si no se pudo leer, crea el fichero con valores por defecto
|
||||||
|
if (!success) {
|
||||||
saveToFile(file_path);
|
saveToFile(file_path);
|
||||||
|
success = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si la versión de fichero no coincide, crea un fichero nuevo con los valores por defecto
|
// Si la versión de fichero no coincide, crea un fichero nuevo con los valores por defecto
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class Game {
|
|||||||
void renderRoomName();
|
void renderRoomName();
|
||||||
|
|
||||||
// Cambia de habitación
|
// Cambia de habitación
|
||||||
bool changeRoom(const std::string& file);
|
bool changeRoom(const std::string& room_path);
|
||||||
|
|
||||||
// Comprueba el teclado
|
// Comprueba el teclado
|
||||||
void checkInput();
|
void checkInput();
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ void LoadingScreen::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Singletones
|
// Singletones
|
||||||
Audio::get()->update(); // Actualiza el objeto Audio
|
Audio::update(); // Actualiza el objeto Audio
|
||||||
Screen::get()->update(); // Actualiza el objeto Screen
|
Screen::get()->update(); // Actualiza el objeto Screen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,13 +29,7 @@ bool checkCollision(const Circle& a, const Circle& b) {
|
|||||||
total_radius_squared = total_radius_squared * total_radius_squared;
|
total_radius_squared = total_radius_squared * total_radius_squared;
|
||||||
|
|
||||||
// Si la distancia entre el centro de los circulos es inferior a la suma de sus radios
|
// Si la distancia entre el centro de los circulos es inferior a la suma de sus radios
|
||||||
if (distanceSquared(a.x, a.y, b.x, b.y) < (total_radius_squared)) {
|
return distanceSquared(a.x, a.y, b.x, b.y) < total_radius_squared;
|
||||||
// Los circulos han colisionado
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// En caso contrario
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detector de colisiones entre un circulo y un rectangulo
|
// Detector de colisiones entre un circulo y un rectangulo
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ double distanceSquared(int x1, int y1, int x2, int y2);
|
|||||||
bool checkCollision(const Circle& a, const Circle& b);
|
bool checkCollision(const Circle& a, const Circle& b);
|
||||||
|
|
||||||
// Detector de colisiones entre un circulo y un rectangulo
|
// Detector de colisiones entre un circulo y un rectangulo
|
||||||
bool checkCollision(const Circle& a, const SDL_FRect& b);
|
bool checkCollision(const Circle& a, const SDL_FRect& rect);
|
||||||
|
|
||||||
// Detector de colisiones entre un dos rectangulos
|
// Detector de colisiones entre un dos rectangulos
|
||||||
bool checkCollision(const SDL_FRect& a, const SDL_FRect& b);
|
bool checkCollision(const SDL_FRect& a, const SDL_FRect& b);
|
||||||
|
|||||||
@@ -1,8 +1,56 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Script para ejecutar clang-tidy recursivamente en todo el código fuente
|
# Script para ejecutar clang-tidy recursivamente en todo el código fuente
|
||||||
# Uso: ./run_clang-tidy.sh [--fix]
|
# Uso:
|
||||||
|
# ./run_clang-tidy.sh [--fix] [--help] [archivos...]
|
||||||
# --fix: Aplica las correcciones automáticamente (opcional)
|
# --fix: Aplica las correcciones automáticamente (opcional)
|
||||||
|
# --help: Muestra la ayuda
|
||||||
|
# archivos: Archivos específicos a analizar (opcional, si no se especifica analiza todos)
|
||||||
|
|
||||||
|
# Función de ayuda
|
||||||
|
show_help() {
|
||||||
|
cat << EOF
|
||||||
|
Uso: ./run_clang-tidy.sh [OPCIONES] [ARCHIVOS...]
|
||||||
|
|
||||||
|
Script para ejecutar clang-tidy en el código fuente del proyecto.
|
||||||
|
|
||||||
|
OPCIONES:
|
||||||
|
--fix Aplica las correcciones automáticamente
|
||||||
|
--help Muestra este mensaje de ayuda
|
||||||
|
|
||||||
|
ARCHIVOS:
|
||||||
|
Si no se especifican archivos, se analizan todos los archivos del proyecto
|
||||||
|
(excluyendo la carpeta external/). Si se especifican archivos, solo se
|
||||||
|
analizan esos archivos específicos.
|
||||||
|
|
||||||
|
EJEMPLOS:
|
||||||
|
# Analizar todo el proyecto
|
||||||
|
./run_clang-tidy.sh
|
||||||
|
|
||||||
|
# Analizar todo el proyecto y aplicar correcciones
|
||||||
|
./run_clang-tidy.sh --fix
|
||||||
|
|
||||||
|
# Analizar un archivo específico
|
||||||
|
./run_clang-tidy.sh source/game/entities/enemy.cpp
|
||||||
|
|
||||||
|
# Analizar múltiples archivos
|
||||||
|
./run_clang-tidy.sh source/game/entities/enemy.cpp source/game/entities/player.cpp
|
||||||
|
|
||||||
|
# Analizar y corregir un archivo específico
|
||||||
|
./run_clang-tidy.sh --fix source/game/entities/enemy.cpp
|
||||||
|
|
||||||
|
# Analizar todos los archivos de una carpeta (usando glob)
|
||||||
|
./run_clang-tidy.sh source/game/entities/*.cpp
|
||||||
|
|
||||||
|
NOTAS:
|
||||||
|
- Se requiere que el directorio build/ exista y contenga compile_commands.json
|
||||||
|
- Los archivos se procesan en paralelo (4 procesos)
|
||||||
|
- Solo se procesan archivos .cpp, .hpp y .h
|
||||||
|
- Las rutas pueden ser relativas o absolutas
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
# Auto-detectar la ubicación del script y calcular rutas del proyecto
|
# Auto-detectar la ubicación del script y calcular rutas del proyecto
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
@@ -10,10 +58,22 @@ PROJECT_DIR=$(cd "$SCRIPT_DIR/../.." && pwd)
|
|||||||
SOURCE_DIR="$PROJECT_DIR/source"
|
SOURCE_DIR="$PROJECT_DIR/source"
|
||||||
BUILD_DIR="$PROJECT_DIR/build"
|
BUILD_DIR="$PROJECT_DIR/build"
|
||||||
|
|
||||||
# Detectar si se pasó el parámetro --fix
|
# Parsear argumentos: separar --fix, --help de archivos
|
||||||
FIX_FLAG=""
|
FIX_FLAG=""
|
||||||
if [[ "$1" == "--fix" ]]; then
|
FILES=()
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [[ "$arg" == "--fix" ]]; then
|
||||||
FIX_FLAG="--fix"
|
FIX_FLAG="--fix"
|
||||||
|
elif [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
|
||||||
|
show_help
|
||||||
|
else
|
||||||
|
FILES+=("$arg")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Mostrar modo
|
||||||
|
if [[ -n "$FIX_FLAG" ]]; then
|
||||||
echo "Modo: Aplicando correcciones automáticamente (--fix)"
|
echo "Modo: Aplicando correcciones automáticamente (--fix)"
|
||||||
else
|
else
|
||||||
echo "Modo: Solo análisis (sin --fix)"
|
echo "Modo: Solo análisis (sin --fix)"
|
||||||
@@ -37,10 +97,51 @@ echo "Fuentes: $SOURCE_DIR"
|
|||||||
echo "Build: $BUILD_DIR"
|
echo "Build: $BUILD_DIR"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Procesar todos los archivos C++ recursivamente desde source/
|
# Si se especificaron archivos, procesarlos directamente
|
||||||
echo "=== Escaneando recursivamente source/ ==="
|
if [[ ${#FILES[@]} -gt 0 ]]; then
|
||||||
find "$SOURCE_DIR" \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -print0 | \
|
echo "=== Procesando ${#FILES[@]} archivo(s) específico(s) ==="
|
||||||
xargs -0 -P4 -I{} bash -c 'echo "Procesando: {}"; clang-tidy {} -p '"$BUILD_DIR"' '"$FIX_FLAG"
|
|
||||||
|
|
||||||
echo
|
# Validar y procesar cada archivo
|
||||||
echo "¡Proceso completado para todos los archivos!"
|
VALID_FILES=()
|
||||||
|
for file in "${FILES[@]}"; do
|
||||||
|
# Convertir a ruta absoluta si es relativa
|
||||||
|
if [[ ! "$file" = /* ]]; then
|
||||||
|
file="$PROJECT_DIR/$file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar que existe
|
||||||
|
if [[ ! -f "$file" ]]; then
|
||||||
|
echo "Advertencia: Archivo no encontrado: $file (omitiendo)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar extensión
|
||||||
|
if [[ "$file" =~ \.(cpp|hpp|h)$ ]]; then
|
||||||
|
VALID_FILES+=("$file")
|
||||||
|
else
|
||||||
|
echo "Advertencia: Archivo no es C++: $file (omitiendo)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Si no hay archivos válidos, salir
|
||||||
|
if [[ ${#VALID_FILES[@]} -eq 0 ]]; then
|
||||||
|
echo "Error: No hay archivos válidos para procesar"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
# Procesar archivos en paralelo
|
||||||
|
printf '%s\n' "${VALID_FILES[@]}" | \
|
||||||
|
xargs -P4 -I{} bash -c 'echo "Procesando: {}"; clang-tidy {} -p '"$BUILD_DIR"' '"$FIX_FLAG"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "¡Proceso completado para ${#VALID_FILES[@]} archivo(s)!"
|
||||||
|
else
|
||||||
|
# Comportamiento original: procesar todos los archivos
|
||||||
|
echo "=== Escaneando recursivamente source/ (excluyendo external/) ==="
|
||||||
|
find "$SOURCE_DIR" \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -not -path "*/external/*" -print0 | \
|
||||||
|
xargs -0 -P4 -I{} bash -c 'echo "Procesando: {}"; clang-tidy {} -p '"$BUILD_DIR"' '"$FIX_FLAG"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "¡Proceso completado para todos los archivos!"
|
||||||
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user