clang-tidy: animated_sprite, asset

This commit is contained in:
2025-07-18 21:27:21 +02:00
parent dabba41179
commit f9877dc82b
5 changed files with 191 additions and 144 deletions

View File

@@ -16,6 +16,9 @@ CheckOptions:
# Miembros privados en snake_case con sufijo _ # Miembros privados en snake_case con sufijo _
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ }
- { key: readability-identifier-naming.ClassMemberCase, value: lower_case }
- { key: readability-identifier-naming.ClassMemberSuffix, value: _ }
# Namespaces en CamelCase # Namespaces en CamelCase
- { key: readability-identifier-naming.NamespaceCase, value: CamelCase } - { key: readability-identifier-naming.NamespaceCase, value: CamelCase }

View File

@@ -1,9 +1,9 @@
#include "animated_sprite.h" #include "animated_sprite.h"
#include <SDL3/SDL.h> // Para SDL_LogWarn, SDL_LogCategory, SDL_LogError #include <SDL3/SDL.h> // Para SDL_LogWarn, SDL_LogCategory, SDL_LogError
#include <stddef.h> // Para size_t
#include <algorithm> // Para min #include <algorithm> // Para min
#include <cstddef> // Para size_t
#include <fstream> // Para basic_istream, basic_ifstream, basic_ios, ifst... #include <fstream> // Para basic_istream, basic_ifstream, basic_ios, ifst...
#include <sstream> // Para basic_stringstream #include <sstream> // Para basic_stringstream
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
@@ -13,7 +13,7 @@
#include "utils.h" // Para printWithDots #include "utils.h" // Para printWithDots
// Carga las animaciones en un vector(Animations) desde un fichero // 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); std::ifstream file(file_path);
if (!file) { if (!file) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
@@ -25,9 +25,10 @@ AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path) {
std::vector<std::string> buffer; std::vector<std::string> buffer;
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(file, line)) {
if (!line.empty()) if (!line.empty()) {
buffer.push_back(line); buffer.push_back(line);
} }
}
return buffer; return buffer;
} }
@@ -37,8 +38,8 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::stri
: MovingSprite(texture) { : MovingSprite(texture) {
// Carga las animaciones // Carga las animaciones
if (!file_path.empty()) { if (!file_path.empty()) {
AnimationsFileBuffer v = loadAnimationsFromFile(file_path); auto buffer = loadAnimationsFromFile(file_path);
loadFromAnimationsFileBuffer(v); loadFromAnimationsFileBuffer(buffer);
} }
} }
@@ -51,11 +52,11 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const Animation
} }
// Obtiene el índice de la animación a partir del nombre // Obtiene el índice de la animación a partir del nombre
int AnimatedSprite::getIndex(const std::string &name) { auto AnimatedSprite::getIndex(const std::string &name) -> int {
auto it = animation_indices_.find(name); auto iterator = animation_indices_.find(name);
if (it != animation_indices_.end()) { if (iterator != animation_indices_.end()) {
// Si se encuentra la animación en el mapa, devuelve su índice // 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 // Si no se encuentra, muestra una advertencia y devuelve -1
@@ -94,7 +95,7 @@ void AnimatedSprite::animate() {
} }
// Comprueba si ha terminado la animación // Comprueba si ha terminado la animación
bool AnimatedSprite::animationIsCompleted() { auto AnimatedSprite::animationIsCompleted() -> bool {
return animations_[current_animation_].completed; return animations_[current_animation_].completed;
} }
@@ -149,89 +150,117 @@ void AnimatedSprite::resetAnimation() {
// Carga la animación desde un vector de cadenas // Carga la animación desde un vector de cadenas
void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source) { void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source) {
float frame_width = 1; AnimationConfig config;
float frame_height = 1;
int frames_per_row = 1;
int max_tiles = 1;
size_t index = 0; size_t index = 0;
while (index < source.size()) { while (index < source.size()) {
std::string line = source.at(index); const std::string& line = source.at(index);
// Parsea el fichero para buscar variables y valores if (line == "[animation]") {
if (line != "[animation]") { index = processAnimationBlock(source, index, config);
// Encuentra la posición del carácter '=' } else {
processConfigLine(line, config);
}
index++;
}
// Pone un valor por defecto
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("="); size_t pos = line.find("=");
if (pos == std::string::npos) {
return;
}
// Procesa las dos subcadenas
if (pos != std::string::npos) {
std::string key = line.substr(0, pos); std::string key = line.substr(0, pos);
int value = std::stoi(line.substr(pos + 1)); int value = std::stoi(line.substr(pos + 1));
if (key == "frame_width")
frame_width = value; if (key == "frame_width") {
else if (key == "frame_height") config.frame_width = value;
frame_height = value; updateFrameCalculations(config);
else } 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()); 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 // Actualiza los cálculos basados en las dimensiones del frame
if (line == "[animation]") { 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; Animation animation;
do { 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++; 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 // Añade la animación al vector de animaciones
animations_.emplace_back(animation); animations_.emplace_back(animation);
// Rellena el mapa con el nombre y el nuevo índice // Rellena el mapa con el nombre y el nuevo índice
animation_indices_[animation.name] = animations_.size() - 1; 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;
} }
// Una vez procesada la línea, aumenta el índice para pasar a la siguiente std::string key = line.substr(0, pos);
index++; std::string value = line.substr(pos + 1);
}
// Pone un valor por defecto if (key == "name") {
setWidth(frame_width); animation.name = value;
setHeight(frame_height); } 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 // Establece la velocidad de la animación

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect #include <SDL3/SDL.h> // Para SDL_FRect
#include <stddef.h> // Para size_t
#include <cstddef> // Para size_t
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para basic_string, string, hash #include <string> // Para basic_string, string, hash
#include <unordered_map> // Para unordered_map #include <unordered_map> // Para unordered_map
@@ -15,45 +15,54 @@ class Texture;
// Estructura de Animación // Estructura de Animación
struct Animation { struct Animation {
static constexpr int DEFAULT_SPEED = 5;
std::string name; // Nombre de la animación std::string name; // Nombre de la animación
std::vector<SDL_FRect> frames; // Frames que componen la animación std::vector<SDL_FRect> frames; // Frames que componen la animación
int speed; // Velocidad de reproducción int speed{DEFAULT_SPEED}; // Velocidad de reproducción
int loop; // Frame de vuelta al terminar (-1 para no repetir) int loop{0}; // Frame de vuelta al terminar (-1 para no repetir)
bool completed; // Indica si la animación ha finalizado bool completed{false}; // Indica si la animación ha finalizado
size_t current_frame; // Frame actual en reproducción size_t current_frame{0}; // Frame actual en reproducción
int counter; // Contador para la animació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 // Alias de tipo para buffer de animaciones
using AnimationsFileBuffer = std::vector<std::string>; using AnimationsFileBuffer = std::vector<std::string>;
// Carga las animaciones desde un fichero en un vector de strings // 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 // Clase AnimatedSprite: Sprite animado que hereda de MovingSprite
class AnimatedSprite : public MovingSprite { class AnimatedSprite : public MovingSprite {
public: public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path); AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer &animations); AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations);
explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(texture) {} explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(texture) {}
virtual ~AnimatedSprite() override = default; ~AnimatedSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
void update() override; // Actualiza la animación void update() override; // Actualiza la animación
// --- Control de animaciones --- // --- Control de animaciones ---
void setCurrentAnimation(const std::string &name = "default", bool reset = true); // Establece la animación por nombre 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 setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice
void resetAnimation(); // Reinicia la animación actual void resetAnimation(); // Reinicia la animación actual
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación 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 auto getAnimationSpeed() const -> size_t { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual
// --- Consultas --- // --- Consultas ---
bool animationIsCompleted(); // Comprueba si la animación ha terminado auto animationIsCompleted() -> bool; // Comprueba si la animación ha terminado
int getIndex(const std::string &name); // Obtiene el índice de una animación por nombre auto getIndex(const std::string& name) -> int; // Obtiene el índice de una animación por nombre
protected: protected:
// --- Datos de animación --- // --- Datos de animación ---
@@ -64,6 +73,11 @@ class AnimatedSprite : public MovingSprite {
std::unordered_map<std::string, int> animation_indices_; std::unordered_map<std::string, int> animation_indices_;
// --- Métodos internos --- // --- Métodos internos ---
void animate(); // Calcula el frame actual de la animación void animate(); // Calcula el frame correspondiente a la animación
void loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source); // Carga animaciones desde un buffer 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)
}; };

View File

@@ -18,7 +18,7 @@ void Asset::init(const std::string &executable_path) { Asset::instance_ = new As
void Asset::destroy() { delete Asset::instance_; } void Asset::destroy() { delete Asset::instance_; }
// Obtiene la instancia // Obtiene la instancia
Asset *Asset::get() { return Asset::instance_; } auto Asset::get() -> Asset * { return Asset::instance_; }
// Añade un elemento a la lista // Añade un elemento a la lista
void Asset::add(const std::string &file, AssetType type, bool required, bool absolute) { 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 // Devuelve la ruta completa a un fichero a partir de una cadena
std::string Asset::get(const std::string &text) const { auto Asset::get(const std::string &text) const -> std::string {
auto it = std::find_if(file_list_.begin(), file_list_.end(), [&text](const auto &f) { auto iterator = std::ranges::find_if(file_list_, [&text](const auto &file) {
return getFileName(f.file) == text; return getFileName(file.file) == text;
}); });
if (it != file_list_.end()) { if (iterator != file_list_.end()) {
return it->file; return iterator->file;
} else { }
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str()); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str());
return ""; return "";
}
} }
// Comprueba que existen todos los elementos // Comprueba que existen todos los elementos
bool Asset::check() const { auto Asset::check() const -> bool {
bool success = true; bool success = true;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES");
@@ -51,8 +50,8 @@ bool Asset::check() const {
// Comprueba si hay ficheros de ese tipo // Comprueba si hay ficheros de ese tipo
bool any = false; bool any = false;
for (const auto &f : file_list_) { for (const auto &file : file_list_) {
if (f.required && f.type == static_cast<AssetType>(type)) { if (file.required && file.type == static_cast<AssetType>(type)) {
any = true; any = true;
} }
} }
@@ -61,15 +60,16 @@ bool Asset::check() const {
if (any) { if (any) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> %s FILES", getTypeName(static_cast<AssetType>(type)).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> %s FILES", getTypeName(static_cast<AssetType>(type)).c_str());
for (const auto &f : file_list_) { for (const auto &file : file_list_) {
if (f.required && f.type == static_cast<AssetType>(type)) { if (file.required && file.type == static_cast<AssetType>(type)) {
success &= checkFile(f.file); success &= checkFile(file.file);
} }
} }
if (success) if (success) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " All files are OK."); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " All files are OK.");
} }
} }
}
// Resultado // Resultado
if (success) { if (success) {
@@ -82,7 +82,7 @@ bool Asset::check() const {
} }
// Comprueba que existe un fichero // 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); std::ifstream file(path);
bool success = file.good(); bool success = file.good();
file.close(); file.close();
@@ -95,7 +95,7 @@ bool Asset::checkFile(const std::string &path) const {
} }
// Devuelve el nombre del tipo de recurso // Devuelve el nombre del tipo de recurso
std::string Asset::getTypeName(AssetType type) const { auto Asset::getTypeName(AssetType type) -> std::string {
switch (type) { switch (type) {
case AssetType::BITMAP: case AssetType::BITMAP:
return "BITMAP"; return "BITMAP";
@@ -121,12 +121,12 @@ std::string Asset::getTypeName(AssetType type) const {
} }
// Devuelve la lista de recursos de un tipo // Devuelve la lista de recursos de un tipo
std::vector<std::string> Asset::getListByType(AssetType type) const { auto Asset::getListByType(AssetType type) const -> std::vector<std::string> {
std::vector<std::string> list; std::vector<std::string> list;
for (auto f : file_list_) { for (auto file : file_list_) {
if (f.type == type) { if (file.type == type) {
list.push_back(f.file); list.push_back(file.file);
} }
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <string> // Para string, basic_string #include <string> // Para string, basic_string
#include <utility>
#include <vector> // Para vector #include <vector> // Para vector
// Tipos de recursos gestionados por Asset // Tipos de recursos gestionados por Asset
@@ -18,28 +19,30 @@ enum class AssetType : int {
}; };
// Clase Asset: gestor de recursos (singleton) // Clase Asset: gestor de recursos (singleton)
class Asset { class Asset { // Gestor de recursos (singleton)
public: public:
// --- Métodos de singleton --- // --- Métodos de singleton ---
static void init(const std::string &executable_path); // Inicializa el objeto Asset static void init(const std::string &executable_path); // Inicializa el objeto Asset
static void destroy(); // Libera 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 --- // --- 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 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 [[nodiscard]] auto get(const std::string &text) const -> std::string; // Obtiene la ruta completa de un recurso a partir de su nombre
bool check() const; // Verifica la existencia de todos los recursos requeridos [[nodiscard]] auto check() const -> bool; // Verifica la existencia de todos los recursos requeridos
std::vector<std::string> getListByType(AssetType type) const; // Devuelve una lista de archivos de un tipo concreto [[nodiscard]] auto getListByType(AssetType type) const -> std::vector<std::string>; // Devuelve una lista de archivos de un tipo concreto
private: private:
// --- Estructura interna para almacenar información de cada recurso --- // --- 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 std::string file; // Ruta del fichero desde la raíz del directorio
AssetType type; // Tipo de recurso AssetType type; // Tipo de recurso
bool required; // Indica si el fichero es obligatorio bool required; // Indica si el fichero es obligatorio
AssetItem(const std::string &filePath, AssetType assetType, bool isRequired) AssetItem(std::string filePath, AssetType assetType, bool isRequired)
: file(filePath), type(assetType), required(isRequired) {} : file(std::move(filePath)), type(assetType), required(isRequired) {} // Constructor
}; };
// --- Variables internas --- // --- Variables internas ---
@@ -48,16 +51,14 @@ class Asset {
std::string executable_path_; // Ruta del ejecutable std::string executable_path_; // Ruta del ejecutable
// --- Métodos internos --- // --- Métodos internos ---
bool checkFile(const std::string &path) const; // Verifica si un archivo existe [[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe (interno)
std::string getTypeName(AssetType type) const; // Devuelve el nombre textual del tipo de recurso [[nodiscard]] static auto getTypeName(AssetType type) -> std::string; // Devuelve el nombre textual del tipo de recurso (interno)
// --- Patrón Singleton --- // --- Patrón Singleton ---
explicit Asset(const std::string &executable_path) explicit Asset(std::string executable_path)
: executable_path_(executable_path) {} : executable_path_(std::move(executable_path)) {} // Constructor privado
~Asset() = default; ~Asset() = default; // Destructor
Asset(const Asset &) = delete;
Asset &operator=(const Asset &) = delete;
// --- Singleton --- // --- Singleton ---
static Asset *instance_; static Asset *instance_; // Instancia singleton
}; };