267 lines
7.3 KiB
C++
267 lines
7.3 KiB
C++
#include "animated_sprite.h"
|
|
#include <stddef.h> // Para size_t
|
|
#include <fstream> // Para basic_ostream, basic_istream, operator<<, basic...
|
|
#include <iostream> // Para cout, cerr
|
|
#include <sstream> // Para basic_stringstream
|
|
#include <stdexcept> // Para runtime_error
|
|
#include "texture.h" // Para Texture
|
|
#include "utils.h" // Para printWithDots
|
|
|
|
// Carga las animaciones en un vector(Animations) desde un fichero
|
|
AnimationsFileBuffer 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<std::string> buffer;
|
|
std::string line;
|
|
while (std::getline(file, line))
|
|
{
|
|
if (!line.empty())
|
|
buffer.push_back(line);
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
// Constructor
|
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path)
|
|
: MovingSprite(texture)
|
|
{
|
|
// Carga las animaciones
|
|
if (!file_path.empty())
|
|
{
|
|
AnimationsFileBuffer v = loadAnimationsFromFile(file_path);
|
|
loadFromAnimationsFileBuffer(v);
|
|
}
|
|
}
|
|
|
|
// Constructor
|
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer &animations)
|
|
: MovingSprite(texture)
|
|
{
|
|
if (!animations.empty())
|
|
{
|
|
loadFromAnimationsFileBuffer(animations);
|
|
}
|
|
}
|
|
|
|
// 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 >= static_cast<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
|
|
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 AnimatedSprite::animationIsCompleted()
|
|
{
|
|
return animations_[current_animation_].completed;
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
// 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 vector de cadenas
|
|
void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source)
|
|
{
|
|
int frame_width = 1;
|
|
int frame_height = 1;
|
|
int frames_per_row = 1;
|
|
int max_tiles = 1;
|
|
|
|
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 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 = texture_->getWidth() / frame_width;
|
|
const int w = texture_->getWidth() / frame_width;
|
|
const int h = texture_->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]")
|
|
{
|
|
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_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 AnimatedSprite::setCurrentAnimationFrame(int num)
|
|
{
|
|
// Descarta valores fuera de rango
|
|
if (num < 0 || num >= static_cast<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
|
|
setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
|
|
} |