Files
coffee_crisis_arcade_edition/source/animated_sprite.cpp

538 lines
14 KiB
C++

#include "animated_sprite.h"
#include <fstream> // for basic_ostream, operator<<, basic_istream, basic...
#include <iostream> // for cout
#include <sstream> // for basic_stringstream
#include "texture.h" // for Texture
// Carga la animación desde un fichero
animatedSprite_t loadAnimationFromFile(std::shared_ptr<Texture> texture, std::string filePath)
{
// Inicializa variables
animatedSprite_t as;
as.texture = texture;
auto framesPerRow = 0;
auto frameWidth = 0;
auto frameHeight = 0;
auto 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
#ifdef VERBOSE
std::cout << "Animation loaded: " << filename << std::endl;
#endif
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 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 auto 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
{
#ifdef VERBOSE
std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
#endif
}
}
} 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
{
#ifdef VERBOSE
std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
#endif
}
// Normaliza valores
if (framesPerRow == 0 && frameWidth > 0)
{
framesPerRow = texture->getWidth() / frameWidth;
}
if (maxTiles == 0 && frameWidth > 0 && frameHeight > 0)
{
const auto w = texture->getWidth() / frameWidth;
const auto h = texture->getHeight() / frameHeight;
maxTiles = w * h;
}
}
}
}
// Cierra el fichero
file.close();
}
// El fichero no se puede abrir
else
{
#ifdef VERBOSE
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
#endif
}
return as;
}
// Constructor
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, std::string file, std::vector<std::string> *buffer)
{
// Copia los punteros
setTexture(texture);
// Carga las animaciones
if (file != "")
{
animatedSprite_t as = loadAnimationFromFile(texture, file);
// Copia los datos de las animaciones
for (auto animation : as.animations)
{
animations_.push_back(animation);
}
}
else if (buffer)
{
loadFromVector(buffer);
}
// Inicializa variables
currentAnimation_ = 0;
}
// Constructor
AnimatedSprite::AnimatedSprite(animatedSprite_t *animation)
{
// Copia los punteros
setTexture(animation->texture);
// Inicializa variables
currentAnimation_ = 0;
// Copia los datos de las animaciones
for (auto a : animation->animations)
{
animations_.push_back(a);
}
}
// Destructor
AnimatedSprite::~AnimatedSprite()
{
animations_.clear();
}
// Obtiene el indice de la animación a partir del nombre
int AnimatedSprite::getIndex(std::string name)
{
auto index = -1;
for (auto a : animations_)
{
index++;
if (a.name == name)
{
return index;
}
}
#ifdef VERBOSE
std::cout << "** Warning: could not find \"" << name.c_str() << "\" animation" << std::endl;
#endif
return -1;
}
// Calcula el frame correspondiente a la animación
void AnimatedSprite::animate()
{
if (!enabled_ || animations_[currentAnimation_].speed == 0)
{
return;
}
// Calcula el frame actual a partir del contador
animations_[currentAnimation_].currentFrame = animations_[currentAnimation_].counter / animations_[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 (animations_[currentAnimation_].currentFrame >= (int)animations_[currentAnimation_].frames.size())
{
if (animations_[currentAnimation_].loop == -1)
{ // Si no hay loop, deja el último frame
animations_[currentAnimation_].currentFrame = animations_[currentAnimation_].frames.size();
animations_[currentAnimation_].completed = true;
}
else
{ // Si hay loop, vuelve al frame indicado
animations_[currentAnimation_].counter = 0;
animations_[currentAnimation_].currentFrame = animations_[currentAnimation_].loop;
}
}
// En caso contrario
else
{
// Escoge el frame correspondiente de la animación
setSpriteClip(animations_[currentAnimation_].frames[animations_[currentAnimation_].currentFrame]);
// Incrementa el contador de la animacion
animations_[currentAnimation_].counter++;
}
}
// Obtiene el número de frames de la animación actual
int AnimatedSprite::getNumFrames()
{
return (int)animations_[currentAnimation_].frames.size();
}
// Establece el frame actual de la animación
void AnimatedSprite::setCurrentFrame(int num)
{
// Descarta valores fuera de rango
if (num >= (int)animations_[currentAnimation_].frames.size())
{
num = 0;
}
// Cambia el valor de la variable
animations_[currentAnimation_].currentFrame = num;
animations_[currentAnimation_].counter = 0;
// Escoge el frame correspondiente de la animación
setSpriteClip(animations_[currentAnimation_].frames[animations_[currentAnimation_].currentFrame]);
}
// Establece el valor del contador
void AnimatedSprite::setAnimationCounter(std::string name, int num)
{
animations_[getIndex(name)].counter = num;
}
// Establece la velocidad de una animación
void AnimatedSprite::setAnimationSpeed(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(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(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_[currentAnimation_].completed;
}
// Devuelve el rectangulo de una animación y frame concreto
SDL_Rect AnimatedSprite::getAnimationClip(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];
}
// Carga la animación desde un vector
bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
{
// Inicializa variables
auto framesPerRow = 0;
auto frameWidth = 0;
auto frameHeight = 0;
auto maxTiles = 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 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
{
#ifdef VERBOSE
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
#endif
success = false;
}
}
} while (line != "[/animation]");
// Añade la animación al vector de animaciones
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
{
#ifdef VERBOSE
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
#endif
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 auto newAnimation = getIndex(name);
if (currentAnimation_ != newAnimation)
{
currentAnimation_ = newAnimation;
animations_[currentAnimation_].currentFrame = 0;
animations_[currentAnimation_].counter = 0;
animations_[currentAnimation_].completed = false;
}
}
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(int index)
{
const auto newAnimation = index;
if (currentAnimation_ != newAnimation)
{
currentAnimation_ = newAnimation;
animations_[currentAnimation_].currentFrame = 0;
animations_[currentAnimation_].counter = 0;
animations_[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)
{
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_[currentAnimation_].currentFrame = 0;
animations_[currentAnimation_].counter = 0;
animations_[currentAnimation_].completed = false;
}