Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Strange animation behaviour  (Read 2432 times)

0 Members and 2 Guests are viewing this topic.

snz

  • Newbie
  • *
  • Posts: 4
    • View Profile
Strange animation behaviour
« on: October 17, 2018, 02:42:02 pm »
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..
« Last Edit: October 17, 2018, 06:17:11 pm by snz »

snz

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Strange animation behaviour
« Reply #1 on: October 17, 2018, 06:37:30 pm »
Look..
Firstly, idle animation starts at 0 and freezes. Then electricity's one cycles normally.. When I click on a window border, idle's frame changes. 

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Strange animation behaviour
« Reply #2 on: October 17, 2018, 08:59:56 pm »
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.

snz

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Strange animation behaviour
« Reply #3 on: October 17, 2018, 09:28:15 pm »
"What have you tried so far to debug it?": I believe the code is alright, but I just dont understand something, that makes this look how it looks. The only thing that chages beahaviour (which i mentioned) was that _loop component. If it is set to true for both - only electicity runs.. When it is set for electricity - only raiden's runs.

"This looks fishy to me. You set this "buffer" to 0 every update and then add this frame's delta" - I initialized buffer with 0, and with clock.restart() method i accumulate delta for single frame. So yeah, you guessed it.

"Presumably clicking on the window border makes it work because it causes the delta to be larger for that one frame." Yes, i believe it is, but the point is - only one animation works normally during the runtime. The question is, why don't they both run normally ?
« Last Edit: October 17, 2018, 09:38:17 pm by snz »

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Strange animation behaviour
« Reply #4 on: October 17, 2018, 11:03:28 pm »
Oops, somehow in my last post I missed that your buffer variable was static. That's going to cause you problems because both _idle and _idleElectro are sharing the same 'buffer'. It would be better as a member variable instead of static in that function.

snz

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Strange animation behaviour
« Reply #5 on: October 17, 2018, 11:31:27 pm »
Damn it! I thougth it would be kind of locally static for them.. Ty