diff --git a/.clang-tidy b/.clang-tidy index 21354e4..a4be83e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -16,6 +16,9 @@ CheckOptions: # Miembros privados en snake_case con sufijo _ - { key: readability-identifier-naming.PrivateMemberCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } + - { key: readability-identifier-naming.ClassMemberCase, value: lower_case } + - { key: readability-identifier-naming.ClassMemberSuffix, value: _ } + # Namespaces en CamelCase - { key: readability-identifier-naming.NamespaceCase, value: CamelCase } diff --git a/source/animated_sprite.cpp b/source/animated_sprite.cpp index 5db7e66..a9451f2 100644 --- a/source/animated_sprite.cpp +++ b/source/animated_sprite.cpp @@ -1,9 +1,9 @@ #include "animated_sprite.h" #include // Para SDL_LogWarn, SDL_LogCategory, SDL_LogError -#include // Para size_t #include // Para min +#include // Para size_t #include // Para basic_istream, basic_ifstream, basic_ios, ifst... #include // Para basic_stringstream #include // Para runtime_error @@ -13,7 +13,7 @@ #include "utils.h" // Para printWithDots // Carga las animaciones en un vector(Animations) desde un fichero -AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path) { +auto loadAnimationsFromFile(const std::string &file_path) -> AnimationsFileBuffer { std::ifstream file(file_path); if (!file) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str()); @@ -25,8 +25,9 @@ AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path) { std::vector buffer; std::string line; while (std::getline(file, line)) { - if (!line.empty()) + if (!line.empty()) { buffer.push_back(line); + } } return buffer; @@ -37,8 +38,8 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr texture, const std::stri : MovingSprite(texture) { // Carga las animaciones if (!file_path.empty()) { - AnimationsFileBuffer v = loadAnimationsFromFile(file_path); - loadFromAnimationsFileBuffer(v); + auto buffer = loadAnimationsFromFile(file_path); + loadFromAnimationsFileBuffer(buffer); } } @@ -51,11 +52,11 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr texture, const Animation } // Obtiene el índice de la animación a partir del nombre -int AnimatedSprite::getIndex(const std::string &name) { - auto it = animation_indices_.find(name); - if (it != animation_indices_.end()) { +auto AnimatedSprite::getIndex(const std::string &name) -> int { + auto iterator = animation_indices_.find(name); + if (iterator != animation_indices_.end()) { // Si se encuentra la animación en el mapa, devuelve su índice - return it->second; + return iterator->second; } // Si no se encuentra, muestra una advertencia y devuelve -1 @@ -94,7 +95,7 @@ void AnimatedSprite::animate() { } // Comprueba si ha terminado la animación -bool AnimatedSprite::animationIsCompleted() { +auto AnimatedSprite::animationIsCompleted() -> bool { return animations_[current_animation_].completed; } @@ -149,89 +150,117 @@ void AnimatedSprite::resetAnimation() { // Carga la animación desde un vector de cadenas void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source) { - float frame_width = 1; - float frame_height = 1; - int frames_per_row = 1; - int max_tiles = 1; - + AnimationConfig config; + size_t index = 0; while (index < source.size()) { - std::string line = source.at(index); - - // Parsea el fichero para buscar variables y valores - if (line != "[animation]") { - // Encuentra la posición del carácter '=' - 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 - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str()); - - frames_per_row = texture_->getWidth() / frame_width; - const int w = texture_->getWidth() / frame_width; - const int h = texture_->getHeight() / frame_height; - max_tiles = w * h; - } - } - - // Si la línea contiene el texto [animation] se realiza el proceso de carga de una animación + const std::string& line = source.at(index); + if (line == "[animation]") { - Animation animation; - do { - index++; - line = source.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, 0, frame_width, frame_height}; - while (getline(ss, tmp, ',')) { - // Comprueba que el tile no sea mayor que el máximo índice 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 - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str()); - } - } while (line != "[/animation]"); - - // Añade la animación al vector de animaciones - animations_.emplace_back(animation); - - // Rellena el mapa con el nombre y el nuevo índice - animation_indices_[animation.name] = animations_.size() - 1; + index = processAnimationBlock(source, index, config); + } else { + processConfigLine(line, config); } - - // Una vez procesada la línea, aumenta el índice para pasar a la siguiente + index++; } - + // Pone un valor por defecto - setWidth(frame_width); - setHeight(frame_height); + setWidth(config.frame_width); + setHeight(config.frame_height); +} + +// Procesa una línea de configuración +void AnimatedSprite::processConfigLine(const std::string& line, AnimationConfig& config) { + size_t pos = line.find("="); + if (pos == std::string::npos) { + return; + } + + std::string key = line.substr(0, pos); + int value = std::stoi(line.substr(pos + 1)); + + if (key == "frame_width") { + config.frame_width = value; + updateFrameCalculations(config); + } else if (key == "frame_height") { + config.frame_height = value; + updateFrameCalculations(config); + } else { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str()); + } +} + +// Actualiza los cálculos basados en las dimensiones del frame +void AnimatedSprite::updateFrameCalculations(AnimationConfig& config) { + config.frames_per_row = texture_->getWidth() / config.frame_width; + const int WIDTH = texture_->getWidth() / config.frame_width; + const int HEIGHT = texture_->getHeight() / config.frame_height; + config.max_tiles = WIDTH * HEIGHT; +} + +// Procesa un bloque completo de animación +auto AnimatedSprite::processAnimationBlock(const AnimationsFileBuffer& source, size_t start_index, const AnimationConfig& config) -> size_t { + Animation animation; + size_t index = start_index + 1; // Salta la línea "[animation]" + + while (index < source.size()) { + const std::string& line = source.at(index); + + if (line == "[/animation]") { + break; + } + + processAnimationParameter(line, animation, config); + index++; + } + + // Añade la animación al vector de animaciones + animations_.emplace_back(animation); + + // Rellena el mapa con el nombre y el nuevo índice + animation_indices_[animation.name] = animations_.size() - 1; + + return index; +} + +// Procesa un parámetro individual de animación +void AnimatedSprite::processAnimationParameter(const std::string& line, Animation& animation, const AnimationConfig& config) { + size_t pos = line.find("="); + if (pos == std::string::npos) { + return; + } + + 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") { + parseFramesParameter(value, animation, config); + } else { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str()); + } +} + +// Parsea el parámetro de frames (lista separada por comas) +void AnimatedSprite::parseFramesParameter(const std::string& frames_str, Animation& animation, const AnimationConfig& config) { + std::stringstream stream(frames_str); + std::string tmp; + SDL_FRect rect = {0, 0, config.frame_width, config.frame_height}; + + while (getline(stream, tmp, ',')) { + const int NUM_TILE = std::stoi(tmp); + if (NUM_TILE <= config.max_tiles) { + rect.x = (NUM_TILE % config.frames_per_row) * config.frame_width; + rect.y = (NUM_TILE / config.frames_per_row) * config.frame_height; + animation.frames.emplace_back(rect); + } + } } // Establece la velocidad de la animación diff --git a/source/animated_sprite.h b/source/animated_sprite.h index c49ecbb..8ebec04 100644 --- a/source/animated_sprite.h +++ b/source/animated_sprite.h @@ -1,8 +1,8 @@ #pragma once #include // Para SDL_FRect -#include // Para size_t +#include // Para size_t #include // Para shared_ptr #include // Para basic_string, string, hash #include // Para unordered_map @@ -15,45 +15,54 @@ class Texture; // Estructura de Animación struct Animation { + static constexpr int DEFAULT_SPEED = 5; + std::string name; // Nombre de la animación std::vector frames; // Frames que componen la animación - int speed; // Velocidad de reproducción - int loop; // Frame de vuelta al terminar (-1 para no repetir) - bool completed; // Indica si la animación ha finalizado - size_t current_frame; // Frame actual en reproducción - int counter; // Contador para la animación + int speed{DEFAULT_SPEED}; // Velocidad de reproducción + int loop{0}; // Frame de vuelta al terminar (-1 para no repetir) + bool completed{false}; // Indica si la animación ha finalizado + size_t current_frame{0}; // Frame actual en reproducción + int counter{0}; // Contador para la animación - Animation() : name(std::string()), speed(5), loop(0), completed(false), current_frame(0), counter(0) {} + Animation() = default; +}; + +struct AnimationConfig { + float frame_width = 1.0F; + float frame_height = 1.0F; + int frames_per_row = 1; + int max_tiles = 1; }; // Alias de tipo para buffer de animaciones using AnimationsFileBuffer = std::vector; // Carga las animaciones desde un fichero en un vector de strings -AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path); +auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer; // Clase AnimatedSprite: Sprite animado que hereda de MovingSprite class AnimatedSprite : public MovingSprite { public: // --- Constructores y destructor --- - AnimatedSprite(std::shared_ptr texture, const std::string &file_path); - AnimatedSprite(std::shared_ptr texture, const AnimationsFileBuffer &animations); + AnimatedSprite(std::shared_ptr texture, const std::string& file_path); + AnimatedSprite(std::shared_ptr texture, const AnimationsFileBuffer& animations); explicit AnimatedSprite(std::shared_ptr texture) : MovingSprite(texture) {} - virtual ~AnimatedSprite() override = default; + ~AnimatedSprite() override = default; // --- Métodos principales --- void update() override; // Actualiza la animación // --- Control de animaciones --- - void setCurrentAnimation(const std::string &name = "default", bool reset = true); // Establece la animación por nombre - void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice - void resetAnimation(); // Reinicia la animación actual - void setAnimationSpeed(size_t value); // Establece la velocidad de la animación - size_t getAnimationSpeed() const { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual + void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre + void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice + void resetAnimation(); // Reinicia la animación actual + void setAnimationSpeed(size_t value); // Establece la velocidad de la animación + auto getAnimationSpeed() const -> size_t { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual // --- Consultas --- - bool animationIsCompleted(); // Comprueba si la animación ha terminado - int getIndex(const std::string &name); // Obtiene el índice de una animación por nombre + auto animationIsCompleted() -> bool; // Comprueba si la animación ha terminado + auto getIndex(const std::string& name) -> int; // Obtiene el índice de una animación por nombre protected: // --- Datos de animación --- @@ -64,6 +73,11 @@ class AnimatedSprite : public MovingSprite { std::unordered_map animation_indices_; // --- Métodos internos --- - void animate(); // Calcula el frame actual de la animación - void loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source); // Carga animaciones desde un buffer + void animate(); // Calcula el frame correspondiente a la animación + void loadFromAnimationsFileBuffer(const AnimationsFileBuffer& source); // Carga la animación desde un vector de cadenas + void processConfigLine(const std::string& line, AnimationConfig& config); // Procesa una línea de configuración + void updateFrameCalculations(AnimationConfig& config); // Actualiza los cálculos basados en las dimensiones del frame + auto processAnimationBlock(const AnimationsFileBuffer& source, size_t start_index, const AnimationConfig& config) -> size_t; // Procesa un bloque completo de animación + static void processAnimationParameter(const std::string& line, Animation& animation, const AnimationConfig& config); // Procesa un parámetro individual de animación + static void parseFramesParameter(const std::string& frames_str, Animation& animation, const AnimationConfig& config); // Parsea el parámetro de frames (lista separada por comas) }; \ No newline at end of file diff --git a/source/asset.cpp b/source/asset.cpp index 2baa3ac..d0a77ff 100644 --- a/source/asset.cpp +++ b/source/asset.cpp @@ -18,7 +18,7 @@ void Asset::init(const std::string &executable_path) { Asset::instance_ = new As void Asset::destroy() { delete Asset::instance_; } // Obtiene la instancia -Asset *Asset::get() { return Asset::instance_; } +auto Asset::get() -> Asset * { return Asset::instance_; } // Añade un elemento a la lista void Asset::add(const std::string &file, AssetType type, bool required, bool absolute) { @@ -27,21 +27,20 @@ void Asset::add(const std::string &file, AssetType type, bool required, bool abs } // Devuelve la ruta completa a un fichero a partir de una cadena -std::string Asset::get(const std::string &text) const { - auto it = std::find_if(file_list_.begin(), file_list_.end(), [&text](const auto &f) { - return getFileName(f.file) == text; +auto Asset::get(const std::string &text) const -> std::string { + auto iterator = std::ranges::find_if(file_list_, [&text](const auto &file) { + return getFileName(file.file) == text; }); - if (it != file_list_.end()) { - return it->file; - } else { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str()); - return ""; + if (iterator != file_list_.end()) { + return iterator->file; } + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str()); + return ""; } // Comprueba que existen todos los elementos -bool Asset::check() const { +auto Asset::check() const -> bool { bool success = true; SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES"); @@ -51,8 +50,8 @@ bool Asset::check() const { // Comprueba si hay ficheros de ese tipo bool any = false; - for (const auto &f : file_list_) { - if (f.required && f.type == static_cast(type)) { + for (const auto &file : file_list_) { + if (file.required && file.type == static_cast(type)) { any = true; } } @@ -61,13 +60,14 @@ bool Asset::check() const { if (any) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> %s FILES", getTypeName(static_cast(type)).c_str()); - for (const auto &f : file_list_) { - if (f.required && f.type == static_cast(type)) { - success &= checkFile(f.file); + for (const auto &file : file_list_) { + if (file.required && file.type == static_cast(type)) { + success &= checkFile(file.file); } } - if (success) + if (success) { SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " All files are OK."); + } } } @@ -82,7 +82,7 @@ bool Asset::check() const { } // Comprueba que existe un fichero -bool Asset::checkFile(const std::string &path) const { +auto Asset::checkFile(const std::string &path) -> bool { std::ifstream file(path); bool success = file.good(); file.close(); @@ -95,7 +95,7 @@ bool Asset::checkFile(const std::string &path) const { } // Devuelve el nombre del tipo de recurso -std::string Asset::getTypeName(AssetType type) const { +auto Asset::getTypeName(AssetType type) -> std::string { switch (type) { case AssetType::BITMAP: return "BITMAP"; @@ -121,12 +121,12 @@ std::string Asset::getTypeName(AssetType type) const { } // Devuelve la lista de recursos de un tipo -std::vector Asset::getListByType(AssetType type) const { +auto Asset::getListByType(AssetType type) const -> std::vector { std::vector list; - for (auto f : file_list_) { - if (f.type == type) { - list.push_back(f.file); + for (auto file : file_list_) { + if (file.type == type) { + list.push_back(file.file); } } diff --git a/source/asset.h b/source/asset.h index ae216df..33f8444 100644 --- a/source/asset.h +++ b/source/asset.h @@ -1,6 +1,7 @@ #pragma once #include // Para string, basic_string +#include #include // Para vector // Tipos de recursos gestionados por Asset @@ -18,28 +19,30 @@ enum class AssetType : int { }; // Clase Asset: gestor de recursos (singleton) -class Asset { +class Asset { // Gestor de recursos (singleton) public: // --- Métodos de singleton --- static void init(const std::string &executable_path); // Inicializa el objeto Asset static void destroy(); // Libera el objeto Asset - static Asset *get(); // Obtiene el puntero al objeto Asset + static auto get() -> Asset *; // Obtiene el puntero al objeto Asset + Asset(const Asset &) = delete; // No se permite copiar + auto operator=(const Asset &) -> Asset & = delete; // No se permite asignar // --- Métodos para la gestión de recursos --- void add(const std::string &file, AssetType type, bool required = true, bool absolute = false); // Añade un recurso a la lista - std::string get(const std::string &text) const; // Obtiene la ruta completa de un recurso a partir de su nombre - bool check() const; // Verifica la existencia de todos los recursos requeridos - std::vector getListByType(AssetType type) const; // Devuelve una lista de archivos de un tipo concreto + [[nodiscard]] auto get(const std::string &text) const -> std::string; // Obtiene la ruta completa de un recurso a partir de su nombre + [[nodiscard]] auto check() const -> bool; // Verifica la existencia de todos los recursos requeridos + [[nodiscard]] auto getListByType(AssetType type) const -> std::vector; // Devuelve una lista de archivos de un tipo concreto private: // --- Estructura interna para almacenar información de cada recurso --- - struct AssetItem { + struct AssetItem { // Estructura para cada recurso std::string file; // Ruta del fichero desde la raíz del directorio AssetType type; // Tipo de recurso bool required; // Indica si el fichero es obligatorio - AssetItem(const std::string &filePath, AssetType assetType, bool isRequired) - : file(filePath), type(assetType), required(isRequired) {} + AssetItem(std::string filePath, AssetType assetType, bool isRequired) + : file(std::move(filePath)), type(assetType), required(isRequired) {} // Constructor }; // --- Variables internas --- @@ -48,16 +51,14 @@ class Asset { std::string executable_path_; // Ruta del ejecutable // --- Métodos internos --- - bool checkFile(const std::string &path) const; // Verifica si un archivo existe - std::string getTypeName(AssetType type) const; // Devuelve el nombre textual del tipo de recurso + [[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe (interno) + [[nodiscard]] static auto getTypeName(AssetType type) -> std::string; // Devuelve el nombre textual del tipo de recurso (interno) // --- Patrón Singleton --- - explicit Asset(const std::string &executable_path) - : executable_path_(executable_path) {} - ~Asset() = default; - Asset(const Asset &) = delete; - Asset &operator=(const Asset &) = delete; + explicit Asset(std::string executable_path) + : executable_path_(std::move(executable_path)) {} // Constructor privado + ~Asset() = default; // Destructor // --- Singleton --- - static Asset *instance_; + static Asset *instance_; // Instancia singleton }; \ No newline at end of file