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

Author Topic: Problems with animation sample code  (Read 3931 times)

0 Members and 1 Guest are viewing this topic.

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Problems with animation sample code
« on: August 12, 2012, 10:00:45 pm »
Hello all!

After a long hiatus, I decided to continue with SFML, and since I needed a simple animation system, I decided to use this one from the wiki. I made some minor modifications to get it to work with SFML2, but I don't think that this is the problem.

My first test animation was a picture consisting of 20 frames, each frame is of size 192 x 192. It worked great.

Then, I tried to animate a player sprite from RPG Maker VX. The sprite sheet consist of 12 sprites, each frame is of size 32 x 32. This one doesn't seems to work as it supposed to.

First, I tried to animate this part only (the first 3 frames of the sheet, so I set 0 as the starting frame and 2 as the end frame).



Normally, it should go in this order from left to righ (0-1-2). But for some reason, it plays in 0-2-1 order. No matter what I set the start/stop frames to, the animation order will be messed up.

The other problem is, when I don't specify the start and the end frame, and just let the system play the whole sheet, it will somehow add an extra frame, consisting of a 3-pixels wide, and 32 pixels tall vertical bar. This happens when the final frame has been reached, and before the system loops back to the first frame.

Again, neither of these problems happen with larger images (for example, with the one that consist of 192 x 192 frames). But I have no idea why is this happening.

Even if my code is largely the same as in the wiki, I post it here, since I could have been made a mistake.

Here's Animation.h:
#ifndef ANIMATION_H
#define ANIMATION_H

#include <SFML\Graphics.hpp>

class AnimSprite : public sf::Sprite
{
public:
        AnimSprite();
        AnimSprite(const sf::Texture &img, int frameWidth, int frameHeight);
       
        ~AnimSprite();

        sf::IntRect AnimSprite::getFramePosition(int frame);

        int getFrameCount();

        void setFrameSize(int frameW, int frameH);
        void setFrame(int frame);
        void setLoopSpeed(float newfps);

        void play();
        void play(int start, int end);
        void stop();
        void update();

private:
        sf::Clock animClock;

        float fps;

        bool isPlaying;

        int loopStart;
        int loopEnd;
        int currentFrame;
        int frameWidth;
        int frameHeight;
};

#endif

And here's Animation.cpp:
#include "Animation.h"

AnimSprite::AnimSprite(void) : sf::Sprite()
{
        this->fps = 1;
        this->currentFrame = 0;
        this->loopStart = 0;
        this->isPlaying = false;
        this->setFrameSize(0, 0);
}

AnimSprite::AnimSprite(const sf::Texture &img, int frameWidth, int frameHeight) : sf::Sprite(img)
{
        this->fps = 1;
        this->currentFrame = 0;
        this->loopStart = 0;
        this->isPlaying = false;
        this->setFrameSize(frameWidth, frameHeight);
}

AnimSprite::~AnimSprite() {     }

int AnimSprite::getFrameCount()
{
        unsigned int horizontal = (this->getTexture()->getSize().x / this->frameWidth);
        unsigned int vertical = (this->getTexture()->getSize().y / this->frameHeight);

        return horizontal * vertical;
}

sf::IntRect AnimSprite::getFramePosition(int frame)
{
        unsigned int horizontal = (this->getTexture()->getSize().x / this->frameWidth);
        unsigned int vertical = (this->getTexture()->getSize().y / this->frameHeight);

        int tileY = frame / horizontal;
        int tileX = frame % horizontal;

        sf::IntRect result(
                tileX * this->frameWidth,
                tileY * this->frameHeight,
                this->frameWidth,
                this->frameHeight);

        return result;
}

void AnimSprite::setFrameSize(int frameW, int frameH)
{
        this->frameWidth = frameW;
        this->frameHeight = frameH;
        this->setTextureRect(sf::IntRect(0, 0, frameW, frameH));
}

void AnimSprite::setFrame(int frame) { this->currentFrame = frame; }

void AnimSprite::setLoopSpeed(float newfps) { this->fps = newfps; }

void AnimSprite::play() { this->play(0, getFrameCount()); }

void AnimSprite::play(int start, int end)
{
        loopStart = start;
        loopEnd = end;
        currentFrame = start;

        isPlaying = true;

        animClock.restart();
}

void AnimSprite::stop() { isPlaying = false; }

void AnimSprite::update()
{
        if(isPlaying)
        {
                int frameCount = (loopEnd + 1) - loopStart;
                float timePosition = (animClock.getElapsedTime().asSeconds() * fps);

                currentFrame = loopStart + (int)timePosition % frameCount;

                this->setTextureRect(getFramePosition(currentFrame));
        }
}

Anybody knows what's going on here? Your help would be greatly appreciated. (I believe it's a trivial problem, but I fail to locate it... :S)

EDIT: Okay, I realized it's a bit hard to understand what the problem is, so here's a compiled binary with the full source code.
« Last Edit: August 12, 2012, 11:21:08 pm by N_K »

kaB00M

  • Full Member
  • ***
  • Posts: 101
    • View Profile
    • Caffeware
    • Email
Re: Problems with animation sample code
« Reply #1 on: August 12, 2012, 11:57:38 pm »
Using this image:

setFrameSize(85, 85);
play(0, 2);
 

Tell me what you get.
« Last Edit: August 13, 2012, 12:13:11 am by kaB00M »



eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problems with animation sample code
« Reply #2 on: August 13, 2012, 12:06:41 am »
setFrameSize(32, 32);
play(0, 2);
 
No that won't work, one frame is 85x85px and not 32px. ;)
But this code does work (tested myself).

setFrameSize(85, 85);
play(0, 2);

Note if you set the framerate of the animation to high it could happen that some frames will get left out or you'll get diffrent animation steps.
The eye recognizes movements as of 24fps but with 3 frames you won't get a nice animation at 24fps. :D
« Last Edit: August 13, 2012, 12:09:15 am by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

kaB00M

  • Full Member
  • ***
  • Posts: 101
    • View Profile
    • Caffeware
    • Email
Re: Problems with animation sample code
« Reply #3 on: August 13, 2012, 12:12:19 am »
Yeah. It's 85x85.



N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Problems with animation sample code
« Reply #4 on: August 13, 2012, 12:27:36 am »
Thanks for all your replies. The actual ingame sprites are 32 x 32. The sample image I've linked has been scaled up for better details.

And it seems that you've encountered one of the problems. Using the linked image, the animation works. The original 32 x 32 doesn't. So, for some reason, there's a size limit, below that limit, the animation will be messed up. What could cause this?

The framerate limit is 60 FPS, just like in all commercial games, so that shouldn't be the problem.
« Last Edit: August 13, 2012, 12:30:21 am by N_K »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problems with animation sample code
« Reply #5 on: August 13, 2012, 12:44:49 am »
I wasn't refering to the framerate limit of the window...
There's a difference between framerate of the window and the frame(chaning)rate of the animation class.
You can set your framerate of the window to any value that you want and you'll get as many frames drawn. But for the animation sprite you have a diffrent animation and if you set this also to 60 frames per second, then you'll need to provide 60 frames i.e. 60 diffrent images for each second of animation. Of course one normally doesn't create as many images but uses for more or less smooth animations 12 diffrent frames and let each frame get drawn twice which will result in a 24fps for one animation cycle.
As for the test image, where you have only 3 frames a speed of 24fps won't give you a usefull animation, but something around 10fps can give you as good of an animation as you can get with 3 frames. ;)

What size limit are you refering to?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Problems with animation sample code
« Reply #6 on: August 13, 2012, 12:56:03 am »
I don't really get it now.

The animation system has no framerate limiter. All I can do is to set the delay between the frames. In my case, for example, it is:

charaAnim.setLoopSpeed(3);

The larger the number, the faster the animation plays. And, as I said before, using a sprite sheet consisting of larger images (like 192 x 192), everything works flawlessly, regardless of the number of frames, or the delay between the frames.

The system starts to fail when I use smaller images. With 32 x 32 sized frames, it doesn't work, with 85 x 85 sized frames, it does. And I'm not sure what causes this.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Problems with animation sample code
« Reply #7 on: August 13, 2012, 01:10:11 am »
You missunderstood the use of the setLoopSpeed function. It does exactly behave as I've described it in my previous post. I've no problems with 32x32 images. For the test I used the following example code, with the scaled down image from your first post to 32x96px.
#include <SFML/Graphics.hpp>

#include "AniSprite.hpp"

int main()
{
        sf::RenderWindow Screen(sf::VideoMode (800, 600, 32), "Ani");
        Screen.setFramerateLimit(60);

        sf::Texture Tex;
        if(!Tex.loadFromFile("happy.png"))
                return EXIT_FAILURE;
        AnimSprite Sprite(Tex,32,32);
        Sprite.setLoopSpeed(10);
        Sprite.play(0,2);

        while( Screen.isOpen() )
        {
                sf::Event Event;
                while (Screen.pollEvent (Event))
                {
                        if (Event.type == sf::Event::Closed)
                                Screen.close();
                }

                Sprite.update();

                Screen.clear();
                Screen.draw(Sprite);
                Screen.display();
        }
}
 
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Problems with animation sample code
« Reply #8 on: August 13, 2012, 02:24:56 am »
You missunderstood the use of the setLoopSpeed function.

I probably did, but it seems to work differently on my machine, then. If I set it to 10, the animation will run faster, but still plays in the incorrect order (and glitches out with the complete, 12-sprite sheet). So, changing it to a higher value will make the animation run faster, but changes nothing else.

It could be just this machine, it could be a video driver issue, or who knows. The best I can do is to discard this animation system, and try a different one, or be a real man and try to write my own.  :)

Thank you anyway.
« Last Edit: August 13, 2012, 02:49:37 am by N_K »

N_K

  • Jr. Member
  • **
  • Posts: 64
    • View Profile
Re: Problems with animation sample code
« Reply #9 on: August 25, 2012, 01:05:12 am »
Okay, sorry for bumping this, but I found the problem.

The wiki states that for SFML2, you need to modify this line:

int frameCount = loopEnd - loopStart;

in the Update() function to this:

int frameCount = (loopEnd+1) - loopStart;

As of the most recent snapshot of SFML2, this is incorrect. Use the original one, it works.