#include "animatedsprite.h" // Carga la animación desde un fichero animatedSprite_t loadFromFile(Texture *texture, std::string filePath) { // Inicializa variables animatedSprite_t as; as.texture = texture; int framesPerRow = 0; int frameWidth = 0; int frameHeight = 0; int maxTiles = 0; const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1); std::ifstream file(filePath); std::string line; // El fichero se puede abrir if (file.good()) { // Procesa el fichero linea a linea std::cout << "Animation loaded: " << filename << std::endl; while (std::getline(file, line)) { // Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación if (line == "[animation]") { t_animation buffer; buffer.counter = 0; buffer.currentFrame = 0; buffer.completed = false; do { std::getline(file, line); // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (pos != (int)line.npos) { if (line.substr(0, pos) == "name") { buffer.name = line.substr(pos + 1, line.length()); } else if (line.substr(0, pos) == "speed") { buffer.speed = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "loop") { buffer.loop = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frames") { // Se introducen los valores separados por comas en un vector std::stringstream ss(line.substr(pos + 1, line.length())); std::string tmp; SDL_Rect rect = {0, 0, frameWidth, frameHeight}; while (getline(ss, tmp, ',')) { // Comprueba que el tile no sea mayor que el maximo indice permitido const int numTile = std::stoi(tmp) > maxTiles ? 0 : std::stoi(tmp); rect.x = (numTile % framesPerRow) * frameWidth; rect.y = (numTile / framesPerRow) * frameHeight; buffer.frames.push_back(rect); } } else { printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str()); } } } while (line != "[/animation]"); // Añade la animación al vector de animaciones as.animations.push_back(buffer); // animation.push_back(buffer); } // En caso contrario se parsea el fichero para buscar las variables y los valores else { // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (pos != (int)line.npos) { if (line.substr(0, pos) == "framesPerRow") { framesPerRow = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frameWidth") { frameWidth = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frameHeight") { frameHeight = std::stoi(line.substr(pos + 1, line.length())); } else { printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str()); } // Normaliza valores if (framesPerRow == 0 && frameWidth > 0) { framesPerRow = texture->getWidth() / frameWidth; } if (maxTiles == 0 && frameWidth > 0 && frameHeight > 0) { const int w = texture->getWidth() / frameWidth; const int h = texture->getHeight() / frameHeight; maxTiles = w * h; } } } } // Cierra el fichero file.close(); } // El fichero no se puede abrir else { printf("Warning: Unable to open %s file\n", filename.c_str()); } // Pone un valor por defecto //setRect({0, 0, frameWidth, frameHeight}); return as; } // Constructor AnimatedSprite::AnimatedSprite(Texture *texture, SDL_Renderer *renderer, std::string file, std::vector *buffer) { // Copia los punteros setTexture(texture); setRenderer(renderer); animatedSprite_t as; // Carga las animaciones if (file != "") { as = loadFromFile(file); // Copia los datos de las animaciones for (auto animation : as.animations) { this->animation.push_back(animation); } } else if (buffer) { loadFromVector(buffer); } // Inicializa variables currentAnimation = 0; } // Constructor AnimatedSprite::AnimatedSprite(SDL_Renderer *renderer, animatedSprite_t as) { // Copia los punteros setTexture(as.texture); setRenderer(renderer); // Inicializa variables currentAnimation = 0; // Copia los datos de las animaciones for (auto animation : as.animations) { this->animation.push_back(animation); } } // Destructor AnimatedSprite::~AnimatedSprite() { for (auto &a : animation) { a.frames.clear(); } animation.clear(); } // Obtiene el indice de la animación a partir del nombre int AnimatedSprite::getIndex(std::string name) { int index = -1; for (auto a : animation) { index++; if (a.name == name) { return index; } } printf("** Warning: could not find \"%s\" animation\n", name.c_str()); return -1; } // Calcula el frame correspondiente a la animación void AnimatedSprite::animate() { if (!enabled || animation.at(currentAnimation).speed == 0) { return; } // Calcula el frame actual a partir del contador animation.at(currentAnimation).currentFrame = animation.at(currentAnimation).counter / animation.at(currentAnimation).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 (animation.at(currentAnimation).currentFrame >= (int)animation.at(currentAnimation).frames.size()) { if (animation.at(currentAnimation).loop == -1) { // Si no hay loop, deja el último frame animation.at(currentAnimation).currentFrame = animation.at(currentAnimation).frames.size(); animation.at(currentAnimation).completed = true; } else { // Si hay loop, vuelve al frame indicado animation.at(currentAnimation).counter = 0; animation.at(currentAnimation).currentFrame = animation.at(currentAnimation).loop; } } // En caso contrario else { // Escoge el frame correspondiente de la animación setSpriteClip(animation.at(currentAnimation).frames.at(animation.at(currentAnimation).currentFrame)); // Incrementa el contador de la animacion animation.at(currentAnimation).counter++; } } // Obtiene el numero de frames de la animación actual int AnimatedSprite::getNumFrames() { return (int)animation.at(currentAnimation).frames.size(); } // Establece el frame actual de la animación void AnimatedSprite::setCurrentFrame(int num) { // Descarta valores fuera de rango if (num >= (int)animation.at(currentAnimation).frames.size()) { num = 0; } // Cambia el valor de la variable animation.at(currentAnimation).currentFrame = num; animation.at(currentAnimation).counter = 0; // Escoge el frame correspondiente de la animación setSpriteClip(animation.at(currentAnimation).frames.at(animation.at(currentAnimation).currentFrame)); } // Establece el valor del contador void AnimatedSprite::setAnimationCounter(std::string name, int num) { animation.at(getIndex(name)).counter = num; } // Establece la velocidad de una animación void AnimatedSprite::setAnimationSpeed(std::string name, int speed) { animation.at(getIndex(name)).counter = speed; } // Establece la velocidad de una animación void AnimatedSprite::setAnimationSpeed(int index, int speed) { animation.at(index).counter = speed; } // Establece si la animación se reproduce en bucle void AnimatedSprite::setAnimationLoop(std::string name, int loop) { animation.at(getIndex(name)).loop = loop; } // Establece si la animación se reproduce en bucle void AnimatedSprite::setAnimationLoop(int index, int loop) { animation.at(index).loop = loop; } // Establece el valor de la variable void AnimatedSprite::setAnimationCompleted(std::string name, bool value) { animation.at(getIndex(name)).completed = value; } // OLD - Establece el valor de la variable void AnimatedSprite::setAnimationCompleted(int index, bool value) { animation.at(index).completed = value; } // Comprueba si ha terminado la animación bool AnimatedSprite::animationIsCompleted() { return animation.at(currentAnimation).completed; } // Devuelve el rectangulo de una animación y frame concreto SDL_Rect AnimatedSprite::getAnimationClip(std::string name, Uint8 index) { return animation.at(getIndex(name)).frames.at(index); } // Devuelve el rectangulo de una animación y frame concreto SDL_Rect AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF) { return animation.at(indexA).frames.at(indexF); } // Carga la animación desde un fichero animatedSprite_t AnimatedSprite::loadFromFile(std::string filePath) { // Inicializa variables animatedSprite_t as; int framesPerRow = 0; int frameWidth = 0; int frameHeight = 0; int maxTiles = 0; const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1); std::ifstream file(filePath); std::string line; // El fichero se puede abrir if (file.good()) { // Procesa el fichero linea a linea std::cout << "Animation loaded: " << filename << std::endl; while (std::getline(file, line)) { // Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación if (line == "[animation]") { t_animation buffer; buffer.counter = 0; buffer.currentFrame = 0; buffer.completed = false; do { std::getline(file, line); // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (pos != (int)line.npos) { if (line.substr(0, pos) == "name") { buffer.name = line.substr(pos + 1, line.length()); } else if (line.substr(0, pos) == "speed") { buffer.speed = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "loop") { buffer.loop = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frames") { // Se introducen los valores separados por comas en un vector std::stringstream ss(line.substr(pos + 1, line.length())); std::string tmp; SDL_Rect rect = {0, 0, frameWidth, frameHeight}; while (getline(ss, tmp, ',')) { // Comprueba que el tile no sea mayor que el maximo indice permitido const int numTile = std::stoi(tmp) > maxTiles ? 0 : std::stoi(tmp); rect.x = (numTile % framesPerRow) * frameWidth; rect.y = (numTile / framesPerRow) * frameHeight; buffer.frames.push_back(rect); } } else { printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str()); } } } while (line != "[/animation]"); // Añade la animación al vector de animaciones as.animations.push_back(buffer); // animation.push_back(buffer); } // En caso contrario se parsea el fichero para buscar las variables y los valores else { // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (pos != (int)line.npos) { if (line.substr(0, pos) == "framesPerRow") { framesPerRow = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frameWidth") { frameWidth = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frameHeight") { frameHeight = std::stoi(line.substr(pos + 1, line.length())); } else { printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str()); } // Normaliza valores if (framesPerRow == 0 && frameWidth > 0) { framesPerRow = texture->getWidth() / frameWidth; } if (maxTiles == 0 && frameWidth > 0 && frameHeight > 0) { const int w = texture->getWidth() / frameWidth; const int h = texture->getHeight() / frameHeight; maxTiles = w * h; } } } } // Cierra el fichero file.close(); } // El fichero no se puede abrir else { printf("Warning: Unable to open %s file\n", filename.c_str()); } // Pone un valor por defecto setRect({0, 0, frameWidth, frameHeight}); // Añade los punteros as.texture = texture; return as; } // Carga la animación desde un vector bool AnimatedSprite::loadFromVector(std::vector *source) { // Inicializa variables int framesPerRow = 0; int frameWidth = 0; int frameHeight = 0; int maxTiles = 0; // Indicador de éxito en el proceso bool success = true; std::string line; // Recorre todo el vector int index = 0; while (index < (int)source->size()) { // Lee desde el vector line = source->at(index); // Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación if (line == "[animation]") { t_animation buffer; buffer.counter = 0; buffer.currentFrame = 0; buffer.completed = false; do { // Aumenta el indice para leer la siguiente linea index++; line = source->at(index); // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (pos != (int)line.npos) { if (line.substr(0, pos) == "name") { buffer.name = line.substr(pos + 1, line.length()); } else if (line.substr(0, pos) == "speed") { buffer.speed = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "loop") { buffer.loop = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frames") { // Se introducen los valores separados por comas en un vector std::stringstream ss(line.substr(pos + 1, line.length())); std::string tmp; SDL_Rect rect = {0, 0, frameWidth, frameHeight}; while (getline(ss, tmp, ',')) { // Comprueba que el tile no sea mayor que el maximo indice permitido const int numTile = std::stoi(tmp) > maxTiles ? 0 : std::stoi(tmp); rect.x = (numTile % framesPerRow) * frameWidth; rect.y = (numTile / framesPerRow) * frameHeight; buffer.frames.push_back(rect); } } else { std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl; success = false; } } } while (line != "[/animation]"); // Añade la animación al vector de animaciones animation.push_back(buffer); } // En caso contrario se parsea el fichero para buscar las variables y los valores else { // Encuentra la posición del caracter '=' int pos = line.find("="); // Procesa las dos subcadenas if (pos != (int)line.npos) { if (line.substr(0, pos) == "framesPerRow") { framesPerRow = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frameWidth") { frameWidth = std::stoi(line.substr(pos + 1, line.length())); } else if (line.substr(0, pos) == "frameHeight") { frameHeight = std::stoi(line.substr(pos + 1, line.length())); } else { std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl; success = false; } // Normaliza valores if (framesPerRow == 0 && frameWidth > 0) { framesPerRow = texture->getWidth() / frameWidth; } if (maxTiles == 0 && frameWidth > 0 && frameHeight > 0) { const int w = texture->getWidth() / frameWidth; const int h = texture->getHeight() / frameHeight; maxTiles = w * h; } } } // Una vez procesada la linea, aumenta el indice para pasar a la siguiente index++; } // Pone un valor por defecto setRect({0, 0, frameWidth, frameHeight}); return success; } // Establece la animacion actual void AnimatedSprite::setCurrentAnimation(std::string name) { const int newAnimation = getIndex(name); if (currentAnimation != newAnimation) { currentAnimation = newAnimation; animation.at(currentAnimation).currentFrame = 0; animation.at(currentAnimation).counter = 0; animation.at(currentAnimation).completed = false; } } // Establece la animacion actual void AnimatedSprite::setCurrentAnimation(int index) { const int newAnimation = index; if (currentAnimation != newAnimation) { currentAnimation = newAnimation; animation.at(currentAnimation).currentFrame = 0; animation.at(currentAnimation).counter = 0; animation.at(currentAnimation).completed = false; } } // Actualiza las variables del objeto void AnimatedSprite::update() { animate(); MovingSprite::update(); } // Establece el rectangulo para un frame de una animación void AnimatedSprite::setAnimationFrames(Uint8 index_animation, Uint8 index_frame, int x, int y, int w, int h) { animation.at(index_animation).frames.push_back({x, y, w, h}); } // OLD - Establece el contador para todas las animaciones void AnimatedSprite::setAnimationCounter(int value) { for (auto &a : animation) { a.counter = value; } } // Reinicia la animación void AnimatedSprite::resetAnimation() { animation.at(currentAnimation).currentFrame = 0; animation.at(currentAnimation).counter = 0; animation.at(currentAnimation).completed = false; }