538 lines
13 KiB
C++
538 lines
13 KiB
C++
#include "animatedsprite.h"
|
|
#include <fstream> // Para basic_ostream, operator<<, basic_istream, basic...
|
|
#include <iostream> // Para cout
|
|
#include <sstream> // Para basic_stringstream
|
|
#include "texture.h" // Para Texture
|
|
|
|
// Carga la animación desde un fichero
|
|
animatedSprite_t loadAnimationFromFile(Texture *texture, std::string filePath, bool verbose)
|
|
{
|
|
// 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
|
|
if (verbose)
|
|
{
|
|
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]")
|
|
{
|
|
animation_t 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
|
|
{
|
|
std::cout << "Warning: file " << filename.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
|
|
as.animations.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: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
}
|
|
|
|
// 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
|
|
{
|
|
if (verbose)
|
|
{
|
|
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
|
|
}
|
|
}
|
|
|
|
return as;
|
|
}
|
|
|
|
// Constructor
|
|
AnimatedSprite::AnimatedSprite(Texture *texture, SDL_Renderer *renderer, std::string file, std::vector<std::string> *buffer)
|
|
{
|
|
// Copia los punteros
|
|
setTexture(texture);
|
|
setRenderer(renderer);
|
|
|
|
// Carga las animaciones
|
|
if (file != "")
|
|
{
|
|
animatedSprite_t as = loadAnimationFromFile(texture, 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 *animation)
|
|
{
|
|
// Copia los punteros
|
|
setTexture(animation->texture);
|
|
setRenderer(renderer);
|
|
|
|
// Inicializa variables
|
|
currentAnimation = 0;
|
|
|
|
// Copia los datos de las animaciones
|
|
for (auto a : animation->animations)
|
|
{
|
|
this->animation.push_back(a);
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
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 (!enabled || animation[currentAnimation].speed == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Calcula el frame actual a partir del contador
|
|
animation[currentAnimation].currentFrame = animation[currentAnimation].counter / animation[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[currentAnimation].currentFrame >= (int)animation[currentAnimation].frames.size())
|
|
{
|
|
if (animation[currentAnimation].loop == -1)
|
|
{ // Si no hay loop, deja el último frame
|
|
animation[currentAnimation].currentFrame = animation[currentAnimation].frames.size();
|
|
animation[currentAnimation].completed = true;
|
|
}
|
|
else
|
|
{ // Si hay loop, vuelve al frame indicado
|
|
animation[currentAnimation].counter = 0;
|
|
animation[currentAnimation].currentFrame = animation[currentAnimation].loop;
|
|
}
|
|
}
|
|
// En caso contrario
|
|
else
|
|
{
|
|
// Escoge el frame correspondiente de la animación
|
|
setSpriteClip(animation[currentAnimation].frames[animation[currentAnimation].currentFrame]);
|
|
|
|
// Incrementa el contador de la animacion
|
|
animation[currentAnimation].counter++;
|
|
}
|
|
}
|
|
|
|
// Obtiene el numero de frames de la animación actual
|
|
int AnimatedSprite::getNumFrames()
|
|
{
|
|
return (int)animation[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[currentAnimation].frames.size())
|
|
{
|
|
num = 0;
|
|
}
|
|
|
|
// Cambia el valor de la variable
|
|
animation[currentAnimation].currentFrame = num;
|
|
animation[currentAnimation].counter = 0;
|
|
|
|
// Escoge el frame correspondiente de la animación
|
|
setSpriteClip(animation[currentAnimation].frames[animation[currentAnimation].currentFrame]);
|
|
}
|
|
|
|
// Establece el valor del contador
|
|
void AnimatedSprite::setAnimationCounter(std::string name, int num)
|
|
{
|
|
animation[getIndex(name)].counter = num;
|
|
}
|
|
|
|
// Establece la velocidad de una animación
|
|
void AnimatedSprite::setAnimationSpeed(std::string name, int speed)
|
|
{
|
|
animation[getIndex(name)].counter = speed;
|
|
}
|
|
|
|
// Establece la velocidad de una animación
|
|
void AnimatedSprite::setAnimationSpeed(int index, int speed)
|
|
{
|
|
animation[index].counter = speed;
|
|
}
|
|
|
|
// Establece si la animación se reproduce en bucle
|
|
void AnimatedSprite::setAnimationLoop(std::string name, int loop)
|
|
{
|
|
animation[getIndex(name)].loop = loop;
|
|
}
|
|
|
|
// Establece si la animación se reproduce en bucle
|
|
void AnimatedSprite::setAnimationLoop(int index, int loop)
|
|
{
|
|
animation[index].loop = loop;
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void AnimatedSprite::setAnimationCompleted(std::string name, bool value)
|
|
{
|
|
animation[getIndex(name)].completed = value;
|
|
}
|
|
|
|
// OLD - Establece el valor de la variable
|
|
void AnimatedSprite::setAnimationCompleted(int index, bool value)
|
|
{
|
|
animation[index].completed = value;
|
|
}
|
|
|
|
// Comprueba si ha terminado la animación
|
|
bool AnimatedSprite::animationIsCompleted()
|
|
{
|
|
return animation[currentAnimation].completed;
|
|
}
|
|
|
|
// Devuelve el rectangulo de una animación y frame concreto
|
|
SDL_Rect AnimatedSprite::getAnimationClip(std::string name, Uint8 index)
|
|
{
|
|
return animation[getIndex(name)].frames[index];
|
|
}
|
|
|
|
// Devuelve el rectangulo de una animación y frame concreto
|
|
SDL_Rect AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF)
|
|
{
|
|
return animation[indexA].frames[indexF];
|
|
}
|
|
|
|
// Carga la animación desde un vector
|
|
bool AnimatedSprite::loadFromVector(std::vector<std::string> *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]")
|
|
{
|
|
animation_t 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[currentAnimation].currentFrame = 0;
|
|
animation[currentAnimation].counter = 0;
|
|
animation[currentAnimation].completed = false;
|
|
}
|
|
}
|
|
|
|
// Establece la animacion actual
|
|
void AnimatedSprite::setCurrentAnimation(int index)
|
|
{
|
|
const int newAnimation = index;
|
|
if (currentAnimation != newAnimation)
|
|
{
|
|
currentAnimation = newAnimation;
|
|
animation[currentAnimation].currentFrame = 0;
|
|
animation[currentAnimation].counter = 0;
|
|
animation[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[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[currentAnimation].currentFrame = 0;
|
|
animation[currentAnimation].counter = 0;
|
|
animation[currentAnimation].completed = false;
|
|
} |