Files
sfml-animated-sprite/animatedsprite.cpp

264 lines
5.1 KiB
C++

#include "animatedsprite.hpp"
#include <array>
#include <cassert>
#include <fstream>
#include <sstream>
namespace Animation
{
sf::IntRect Animation::GetFrame(unsigned frameNumber, bool const bounced) const
{
assert(frameNumber < frameCount);
if(reverse != bounced)
frameNumber = frameCount - (frameNumber + 1);
unsigned const x = frameOrigin.x + (frameNumber * frameStep.x);
unsigned const y = frameOrigin.y + (frameNumber * frameStep.y);
return sf::IntRect(x, y, frameSize.x, frameSize.y);
}
Animation::Animation()
: frameOrigin(0, 0),
frameSize(0, 0),
frameStep(0, 0),
frameCount(0),
frameTime(0),
reverse(false),
loop(false),
bounce(false)
{}
std::unordered_map<std::string, Animation> LoadFromFile(std::string const & filepath)
{
std::array<std::string, 9> const properties =
{
"frame-origin",
"frame-size",
"frame-step",
"frame-count",
"frame-time",
"reverse",
"loop",
"bounce"
};
std::unordered_map<std::string, Animation> animations;
std::ifstream file(filepath);
if(!file.is_open())
return animations;
Animation candidate;
std::string candidateName;
while(file.good())
{
std::string lineRaw;
std::getline(file, lineRaw);
if(lineRaw.size() == 0 || lineRaw[0] == '#')
continue;
std::stringstream line(lineRaw);
std::string key;
line >> key;
if(lineRaw[0] == '\t' && candidateName.size() > 0)
{
for(std::size_t i = 0; i < properties.size(); ++i)
{
if(properties[i].compare(key) == 0)
{
switch(i)
{
case 0:
line >> candidate.frameOrigin.x;
line >> candidate.frameOrigin.y;
break;
case 1:
line >> candidate.frameSize.x;
line >> candidate.frameSize.y;
break;
case 2:
line >> candidate.frameStep.x;
line >> candidate.frameStep.y;
break;
case 3:
line >> candidate.frameCount;
break;
case 4:
line >> candidate.frameTime;
break;
case 5:
candidate.reverse = true;
break;
case 6:
candidate.loop = true;
break;
case 7:
candidate.loop = true;
candidate.bounce = true;
break;
}
break;
}
}
}
else if(key.compare("animation") == 0)
{
if(candidateName.size() > 0)
{
animations[candidateName] = candidate;
}
candidate = Animation();
line >> candidateName;
}
else
{
if(candidateName.size() > 0)
{
animations[candidateName] = candidate;
}
candidateName.resize(0);
}
}
file.close();
if(candidateName.size() > 0)
{
animations[candidateName] = candidate;
candidateName.resize(0);
}
return animations;
}
void Sprite::SetFrame()
{
assert(currentAnimation != nullptr);
sf::IntRect textureRect = currentAnimation->GetFrame(currentFrame, bouncing);
if(isFlippedHorizontally)
{
textureRect.left += textureRect.width;
textureRect.width *= -1;
}
if(isFlippedVertically)
{
textureRect.top += textureRect.height;
textureRect.height *= -1;
}
setTextureRect(textureRect);
}
bool Sprite::IsAnimationFinished() const
{
assert(currentAnimation != nullptr);
return currentFrame == (currentAnimation->frameCount - 1) && !currentAnimation->loop;
}
void Sprite::SetHorizontalFlip(const bool v)
{
if(v != isFlippedHorizontally)
{
isFlippedHorizontally = v;
SetFrame();
}
}
void Sprite::SetVerticalFlip(const bool v)
{
if(v != isFlippedVertically)
{
isFlippedVertically = v;
SetFrame();
}
}
bool Sprite::IsFlippedHorizontally() const
{
return isFlippedHorizontally;
}
bool Sprite::IsFlippedVertically() const
{
return isFlippedVertically;
}
void Sprite::ResetAnimation()
{
currentFrame = 0U;
currentFrameTime = 0U;
bouncing = false;
SetFrame();
}
bool Sprite::SetAnimation(const std::string & name)
{
auto const candidate = animations.find(name);
if(candidate == animations.cend())
{
return false;
}
currentAnimation = &(candidate->second);
ResetAnimation();
return true;
}
void Sprite::Update(const sf::Time & elapsed)
{
assert(currentAnimation != nullptr);
if(IsAnimationFinished())
{
return;
}
currentFrameTime += elapsed.asMilliseconds();
if(currentFrameTime < currentAnimation->frameTime)
{
return;
}
unsigned const steps = currentFrameTime / currentAnimation->frameTime;
currentFrameTime -= currentAnimation->frameTime * steps;
currentFrame += steps;
if(currentFrame >= currentAnimation->frameCount)
{
currentFrame = currentFrame % currentAnimation->frameCount;
if(currentAnimation->bounce)
bouncing = !bouncing;
}
SetFrame();
}
void Sprite::UpdateFromOther(const Sprite & parent)
{
if(currentFrame != parent.currentFrame)
{
currentFrame = parent.currentFrame;
bouncing = parent.bouncing;
SetFrame();
}
}
Sprite::Sprite(std::unordered_map<std::string, Animation> const & _animations,
std::string const & animation,
sf::Texture const & texture)
: sf::Sprite(texture),
animations(_animations),
currentAnimation(nullptr)
{
SetAnimation(animation);
}
}