264 lines
5.1 KiB
C++
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);
|
|
}
|
|
}
|