#include "animatedsprite.hpp" #include #include #include #include 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 * frameMargin.x) + (frameNumber * frameStep.x); unsigned const y = frameOrigin.y + (frameNumber * frameMargin.y) + (frameNumber * frameStep.y); return sf::IntRect(x, y, frameSize.x, frameSize.y); } Animation::Animation() : frameOrigin(0, 0), frameSize(0, 0), frameStep(0, 0), frameMargin(0, 0), frameCount(0), frameTime(0), reverse(false), loop(false), bounce(false) {} std::unordered_map LoadFromFile(std::string const & filepath) { std::array const properties = { "frame-origin", "frame-size", "frame-step", "frame-margin", "frame-count", "frame-time", "reverse", "loop", "bounce" }; std::unordered_map 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.frameMargin.x; line >> candidate.frameMargin.y; break; case 4: line >> candidate.frameCount; break; case 5: line >> candidate.frameTime; break; case 6: candidate.reverse = true; break; case 7: candidate.loop = true; break; case 8: 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 const & _animations, std::string const & animation, sf::Texture const & texture) : sf::Sprite(texture), animations(_animations), currentAnimation(nullptr) { SetAnimation(animation); } }