531 lines
14 KiB
C++
531 lines
14 KiB
C++
#include "animated_sprite.h"
|
|
#include <algorithm> // for copy
|
|
#include <fstream> // for basic_ostream, operator<<, basic_istream, basic...
|
|
#include <iostream> // for cout
|
|
#include <iterator> // for back_insert_iterator, back_inserter
|
|
#include <sstream> // for basic_stringstream
|
|
#include "texture.h" // for Texture
|
|
#include "utils.h"
|
|
|
|
// Carga las animaciones en un vector(Animations) desde un fichero
|
|
Animations loadAnimationsFromFile(const std::string &file_path)
|
|
{
|
|
std::vector<std::string> buffer;
|
|
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);
|
|
}
|
|
|
|
std::string line;
|
|
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
|
|
|
|
while (std::getline(file, line))
|
|
{
|
|
buffer.push_back(line);
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
// Constructor
|
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path)
|
|
: MovingSprite(texture),
|
|
current_animation_(0)
|
|
{
|
|
// Carga las animaciones
|
|
if (!file_path.empty())
|
|
{
|
|
animations_ = loadFromFile(file_path);
|
|
}
|
|
}
|
|
|
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const Animations &animations)
|
|
: MovingSprite(texture),
|
|
current_animation_(0)
|
|
{
|
|
if (!animations.empty())
|
|
{
|
|
loadFromVector(animations);
|
|
}
|
|
}
|
|
|
|
// Constructor
|
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture)
|
|
: MovingSprite(texture),
|
|
current_animation_(0) {}
|
|
|
|
// Destructor
|
|
AnimatedSprite::~AnimatedSprite()
|
|
{
|
|
animations_.clear();
|
|
}
|
|
|
|
// Obtiene el indice de la animación a partir del nombre
|
|
int AnimatedSprite::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 AnimatedSprite::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 >= (int)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
|
|
setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
|
|
|
|
// Incrementa el contador de la animacion
|
|
animations_[current_animation_].counter++;
|
|
}
|
|
}
|
|
|
|
// Obtiene el número de frames de la animación actual
|
|
int AnimatedSprite::getNumFrames()
|
|
{
|
|
return (int)animations_[current_animation_].frames.size();
|
|
}
|
|
|
|
// Establece el frame actual de la animación
|
|
void AnimatedSprite::setCurrentFrame(int num)
|
|
{
|
|
// Descarta valores fuera de rango
|
|
if (num >= (int)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
|
|
setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
|
|
}
|
|
|
|
// Establece el valor del contador
|
|
void AnimatedSprite::setAnimationCounter(const std::string &name, int num)
|
|
{
|
|
animations_[getIndex(name)].counter = num;
|
|
}
|
|
|
|
// Establece la velocidad de una animación
|
|
void AnimatedSprite::setAnimationSpeed(const std::string &name, int speed)
|
|
{
|
|
animations_[getIndex(name)].counter = speed;
|
|
}
|
|
|
|
// Establece la velocidad de una animación
|
|
void AnimatedSprite::setAnimationSpeed(int index, int speed)
|
|
{
|
|
animations_[index].counter = speed;
|
|
}
|
|
|
|
// Establece si la animación se reproduce en bucle
|
|
void AnimatedSprite::setAnimationLoop(const std::string &name, int loop)
|
|
{
|
|
animations_[getIndex(name)].loop = loop;
|
|
}
|
|
|
|
// Establece si la animación se reproduce en bucle
|
|
void AnimatedSprite::setAnimationLoop(int index, int loop)
|
|
{
|
|
animations_[index].loop = loop;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void AnimatedSprite::setAnimationCompleted(const std::string &name, bool value)
|
|
{
|
|
animations_[getIndex(name)].completed = value;
|
|
}
|
|
|
|
// OLD - Establece el valor de la variable
|
|
void AnimatedSprite::setAnimationCompleted(int index, bool value)
|
|
{
|
|
animations_[index].completed = value;
|
|
}
|
|
|
|
// Comprueba si ha terminado la animación
|
|
bool AnimatedSprite::animationIsCompleted()
|
|
{
|
|
return animations_[current_animation_].completed;
|
|
}
|
|
|
|
// Devuelve el rectangulo de una animación y frame concreto
|
|
SDL_Rect AnimatedSprite::getAnimationClip(const std::string &name, Uint8 index)
|
|
{
|
|
return animations_[getIndex(name)].frames[index];
|
|
}
|
|
|
|
// Devuelve el rectangulo de una animación y frame concreto
|
|
SDL_Rect AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF)
|
|
{
|
|
return animations_[indexA].frames[indexF];
|
|
}
|
|
|
|
// Establece la animacion actual
|
|
void AnimatedSprite::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;
|
|
}
|
|
}
|
|
|
|
// Establece la animacion actual
|
|
void AnimatedSprite::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;
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
animations_[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 : animations_)
|
|
{
|
|
a.counter = value;
|
|
}
|
|
}
|
|
|
|
// Reinicia la animación
|
|
void AnimatedSprite::resetAnimation()
|
|
{
|
|
animations_[current_animation_].current_frame = 0;
|
|
animations_[current_animation_].counter = 0;
|
|
animations_[current_animation_].completed = false;
|
|
}
|
|
|
|
// Carga la animación desde un fichero
|
|
std::vector<Animation> AnimatedSprite::loadFromFile(const std::string &file_path)
|
|
{
|
|
// Inicializa variables
|
|
std::vector<Animation> animations;
|
|
auto frames_per_row = 0;
|
|
auto frame_width = 0;
|
|
auto frame_height = 0;
|
|
auto max_tiles = 0;
|
|
|
|
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
|
|
std::ifstream file(file_path);
|
|
std::string line;
|
|
|
|
// El fichero se puede abrir
|
|
if (file.good())
|
|
{
|
|
// Procesa el fichero linea a linea
|
|
std::cout << "Animation loaded: " << file_name << 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]")
|
|
{
|
|
Animation animation = Animation();
|
|
|
|
do
|
|
{
|
|
std::getline(file, line);
|
|
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
|
|
// Procesa las dos subcadenas
|
|
if (pos != static_cast<int>(line.npos))
|
|
{
|
|
if (line.substr(0, pos) == "name")
|
|
{
|
|
animation.name = line.substr(pos + 1, line.length());
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "speed")
|
|
{
|
|
animation.speed = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "loop")
|
|
{
|
|
animation.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, frame_width, frame_height};
|
|
while (getline(ss, tmp, ','))
|
|
{
|
|
// Comprueba que el tile no sea mayor que el maximo indice permitido
|
|
const auto num_tile = std::stoi(tmp) > max_tiles ? 0 : std::stoi(tmp);
|
|
rect.x = (num_tile % frames_per_row) * frame_width;
|
|
rect.y = (num_tile / frames_per_row) * frame_height;
|
|
animation.frames.push_back(rect);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
}
|
|
}
|
|
} while (line != "[/animation]");
|
|
|
|
// Añade la animación al vector de animaciones
|
|
animations.push_back(animation);
|
|
}
|
|
|
|
// 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) == "frames_per_row")
|
|
{
|
|
frames_per_row = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "frame_width")
|
|
{
|
|
frame_width = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "frame_height")
|
|
{
|
|
frame_height = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else
|
|
{
|
|
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
}
|
|
|
|
// Normaliza valores
|
|
if (frames_per_row == 0 && frame_width > 0)
|
|
{
|
|
frames_per_row = texture_->getWidth() / frame_width;
|
|
}
|
|
|
|
if (max_tiles == 0 && frame_width > 0 && frame_height > 0)
|
|
{
|
|
const auto w = texture_->getWidth() / frame_width;
|
|
const auto h = texture_->getHeight() / frame_height;
|
|
max_tiles = w * h;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cierra el fichero
|
|
file.close();
|
|
}
|
|
// El fichero no se puede abrir
|
|
else
|
|
{
|
|
std::cout << "Warning: Unable to open " << file_name.c_str() << " file" << std::endl;
|
|
}
|
|
|
|
// Pone un valor por defecto
|
|
setWidth(frame_width);
|
|
setHeight(frame_height);
|
|
|
|
return animations;
|
|
}
|
|
|
|
// Carga la animación desde un vector
|
|
bool AnimatedSprite::loadFromVector(const Animations &source)
|
|
{
|
|
// Inicializa variables
|
|
auto frames_per_row = 0;
|
|
auto frame_width = 0;
|
|
auto frame_height = 0;
|
|
auto max_tiles = 0;
|
|
|
|
// Indicador de éxito en el proceso
|
|
auto success = true;
|
|
std::string line;
|
|
|
|
// Recorre todo el vector
|
|
auto 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]")
|
|
{
|
|
Animation animation = Animation();
|
|
|
|
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 != static_cast<int>(line.npos))
|
|
{
|
|
if (line.substr(0, pos) == "name")
|
|
{
|
|
animation.name = line.substr(pos + 1, line.length());
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "speed")
|
|
{
|
|
animation.speed = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "loop")
|
|
{
|
|
animation.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, 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) > max_tiles ? 0 : std::stoi(tmp);
|
|
rect.x = (num_tile % frames_per_row) * frame_width;
|
|
rect.y = (num_tile / frames_per_row) * frame_height;
|
|
animation.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
|
|
animations_.push_back(animation);
|
|
}
|
|
|
|
// 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) == "frames_per_row")
|
|
{
|
|
frames_per_row = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "frame_width")
|
|
{
|
|
frame_width = std::stoi(line.substr(pos + 1, line.length()));
|
|
}
|
|
|
|
else if (line.substr(0, pos) == "frame_height")
|
|
{
|
|
frame_height = 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 (frames_per_row == 0 && frame_width > 0)
|
|
{
|
|
frames_per_row = texture_->getWidth() / frame_width;
|
|
}
|
|
|
|
if (max_tiles == 0 && frame_width > 0 && frame_height > 0)
|
|
{
|
|
const int w = texture_->getWidth() / frame_width;
|
|
const int h = texture_->getHeight() / frame_height;
|
|
max_tiles = w * h;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
|
|
return success;
|
|
} |