Im writing MK clone.
I wrote Animation class:
#ifndef ANIMATOR_H
#define ANIMATOR_H
#include <vector>
#include "SFML\Graphics.hpp"
class Animator {
public:
Animator();
~Animator();
void addFrame(sf::IntRect frame);
void play(sf::Time duration, bool loop);
bool isPlaying() const;
void update(sf::Time delta);
// Sprite contains current frame
void switchFrame(sf::Sprite& sprite);
private:
std::vector<sf::IntRect> _frames;
unsigned _currentFrame;
bool _loop;
bool _isPlaying;
sf::Time _duration;
};
#include "Animator.h"
Animator::Animator() : _currentFrame(0), _isPlaying(false), _duration(sf::Time::Zero), _loop(false) {}
Animator::~Animator() {
}
void Animator::addFrame(sf::IntRect frame) {
_frames.push_back(frame);
}
void Animator::play(sf::Time duration, bool loop) {
_isPlaying = true;
_duration = duration;
_loop = loop;
}
bool Animator::isPlaying() const {
return _isPlaying;
}
void Animator::update(sf::Time delta) {
if (!isPlaying())
return;
// Local time buffer
static sf::Time buffer = sf::Time::Zero;
// Update with an elapsed time
buffer += delta;
// Compute single frame duration
sf::Time frameDuration = _duration / static_cast<float>(_frames.size());
// Time to switch frame
if (buffer >= frameDuration) {
_currentFrame++;
// If looping animation is not allowed
if (_currentFrame >= _frames.size()) {
if (!_loop)
_isPlaying = false;
_currentFrame = 0;
}
buffer -= frameDuration;
}
printf("%d\n", _currentFrame);
}
void Animator::switchFrame(sf::Sprite& sprite) {
sprite.setTextureRect(_frames[_currentFrame]);
}
#endif // ANIMATOR_H
And in raiden's class derived from Character class, with is derived from Transformable and Drawable, created 2 animators: idle and idle_electricity.
I wanted them to play simultaneously..
#ifndef RAIDEN_H
#define RAIDEN_H
#include "Character.h"
#include "Animator.h"
class Raiden : public Character {
public:
Raiden();
~Raiden();
virtual void update(sf::Time delta);
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
sf::Texture _spritesheet;
sf::Sprite _visual;
sf::Sprite _visualElectro;
Animator _idle;
Animator _idleElectro;
};
#endif // RAIDEN_H
Raiden::Raiden() {
if (!_spritesheet.loadFromFile("Assets/raiden-s.png"))
throw std::runtime_error("Unable to load raiden's spritesheet");
_visual.setTexture(_spritesheet);
_visualElectro.setTexture(_spritesheet);
setOrigin(27, 51);
setPosition(300, 300);
// Idle animation
for (unsigned i = 1; i <= 271; i += 54)
_idle.addFrame(sf::IntRect(i, 14, 54, 102));
// Idle electricity animation
for (unsigned i = 1; i <= 811; i += 54)
_idleElectro.addFrame(sf::IntRect(i, 132, 54, 102));
_idle.play(sf::seconds(1), true);
_idleElectro.play(sf::seconds(2), true);
}
Raiden::~Raiden() {
}
void Raiden::update(sf::Time delta) {
// Animation update
_idle.update(delta);
_idle.switchFrame(_visual);
_idleElectro.update(delta);
_idleElectro.switchFrame(_visualElectro);
Character::update(delta);
}
void Raiden::draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
target.draw(_visual, states);
target.draw(_visualElectro, states);
}
What is strange? (Note printf("%d\n", _currentFrame); in animator update method )
While both of them are being played, only electicity's one animation is playing, but idle's one (raiden itself) stands still without changes.
For idle's one it prints 0 as currentFrame, for electricity's one - normally cycled
But, when electicity's one _loop is being set to false, it's stopped (which is ok), but idle's one starts cycling thru frames.. (animation is played) Why is that ?
+ dont know why, after resizing a window, currentFrame of idle's one changes (when both _loop are being set to true..) I mean, i feel like _idle_electricity's animation depends on time, but _idle's one only to window resizing or window clicks..
What have you tried so far to debug it?
static sf::Time buffer = sf::Time::Zero;
// Update with an elapsed time
buffer += delta;
This looks fishy to me. You set this "buffer" to 0 every update and then add this frame's delta. As you have it right now, if the delta is always small then the buffer will always be less than frameDuration. I would guess you actually want to accumulate the deltas over time.
Presumably clicking on the window border makes it work because it causes the delta to be larger for that one frame.