#include "s_animated_sprite.h" #include // Para size_t #include // Para basic_ostream, basic_istream, operator<<, basic... #include // Para cout, cerr #include // Para basic_stringstream #include // Para runtime_error #include "surface.h" // Para Surface #include "utils.h" // Para printWithDots // Carga las animaciones en un vector(Animations) desde un fichero Animations loadAnimationsFromFile(const std::string &file_path) { std::ifstream file(file_path); if (!file) { std::cerr << "Error: Fichero no encontrado " << file_path << std::endl; throw std::runtime_error("Fichero no encontrado: " + file_path); } printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]"); std::vector buffer; std::string line; while (std::getline(file, line)) { if (!line.empty()) buffer.push_back(line); } return buffer; } // Constructor SAnimatedSprite::SAnimatedSprite(std::shared_ptr surface, const std::string &file_path) : SMovingSprite(surface) { // Carga las animaciones if (!file_path.empty()) { Animations v = loadAnimationsFromFile(file_path); setAnimations(v); } } // Constructor SAnimatedSprite::SAnimatedSprite(std::shared_ptr surface, const Animations &animations) : SMovingSprite(surface) { if (!animations.empty()) { setAnimations(animations); } } // Obtiene el indice de la animación a partir del nombre int SAnimatedSprite::getIndex(const std::string &name) { auto index = -1; for (const auto &a : animations_) { index++; if (a.name == name) { return index; } } std::cout << "** Warning: could not find \"" << name.c_str() << "\" animation" << std::endl; return -1; } // Calcula el frame correspondiente a la animación void SAnimatedSprite::animate() { if (animations_[current_animation_].speed == 0) { return; } // Calcula el frame actual a partir del contador animations_[current_animation_].current_frame = animations_[current_animation_].counter / animations_[current_animation_].speed; // Si alcanza el final de la animación, reinicia el contador de la animación // en función de la variable loop y coloca el nuevo frame if (animations_[current_animation_].current_frame >= static_cast(animations_[current_animation_].frames.size())) { if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame animations_[current_animation_].current_frame = animations_[current_animation_].frames.size(); animations_[current_animation_].completed = true; } else { // Si hay loop, vuelve al frame indicado animations_[current_animation_].counter = 0; animations_[current_animation_].current_frame = animations_[current_animation_].loop; } } // En caso contrario else { // Escoge el frame correspondiente de la animación setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); // Incrementa el contador de la animacion animations_[current_animation_].counter++; } } // Comprueba si ha terminado la animación bool SAnimatedSprite::animationIsCompleted() { return animations_[current_animation_].completed; } // Establece la animacion actual void SAnimatedSprite::setCurrentAnimation(const std::string &name) { const auto new_animation = getIndex(name); if (current_animation_ != new_animation) { current_animation_ = new_animation; animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; animations_[current_animation_].completed = false; setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); } } // Establece la animacion actual void SAnimatedSprite::setCurrentAnimation(int index) { const auto new_animation = index; if (current_animation_ != new_animation) { current_animation_ = new_animation; animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; animations_[current_animation_].completed = false; setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); } } // Actualiza las variables del objeto void SAnimatedSprite::update() { animate(); SMovingSprite::update(); } // Reinicia la animación void SAnimatedSprite::resetAnimation() { animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; animations_[current_animation_].completed = false; } // Carga la animación desde un vector de cadenas void SAnimatedSprite::setAnimations(const Animations &animations) { int frame_width = 1; int frame_height = 1; int frames_per_row = 1; int max_tiles = 1; size_t index = 0; while (index < animations.size()) { std::string line = animations.at(index); // Parsea el fichero para buscar variables y valores if (line != "[animation]") { // Encuentra la posición del caracter '=' 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; const int w = surface_->getWidth() / frame_width; const int h = surface_->getHeight() / frame_height; max_tiles = w * h; } } // Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación if (line == "[animation]") { AnimationData animation; 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); 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_Rect rect = {0, 0, 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); } // Una vez procesada la linea, aumenta el indice para pasar a la siguiente index++; } // Pone un valor por defecto setWidth(frame_width); setHeight(frame_height); } // Establece el frame actual de la animación void SAnimatedSprite::setCurrentAnimationFrame(int num) { // Descarta valores fuera de rango if (num < 0 || num >= static_cast(animations_[current_animation_].frames.size())) { num = 0; } // Cambia el valor de la variable animations_[current_animation_].current_frame = num; animations_[current_animation_].counter = 0; // Escoge el frame correspondiente de la animación setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); }