Search code examples
c++sfml

SFML Animation playing only one frame


I am trying to get my animation to cycle through three images when a key is pressed. Currently it switches image only if key pressed. Else way it is not seemed on screen. I have tried to update my animation but it causes the animation to get stuck in one place. Could anyone explain to me how to go about implementing this please?

Animation.h

#pragma once

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Sprite.hpp>
class Animation
{
    bool reversed;

    
    unsigned short animation_iterator;
    unsigned short animation_speed;
    unsigned short current_frame;
    unsigned short frame_width;
    unsigned short total_frames;

    sf::Sprite sprite;

    sf::Texture texture;
public:
    Animation(const unsigned short i_frame_width, const std::string& i_texture_location, const unsigned short i_animation_speed = 1);

    void draw(sf::RenderWindow& i_window);
    void set_animation_speed(const unsigned short i_animation_speed);
    void set_reversed(const bool i_value);
    void set_position(const short i_x, const short i_y);
    void set_texture_location(const std::string& i_texture_location);
    void update();
};
Animation::Animation(const unsigned short i_frame_width, const std::string& i_texture_location, const unsigned short i_animation_speed) :
    reversed(0),
    animation_iterator(0),
    animation_speed(0),
    current_frame(0),
    frame_width(i_frame_width)
{
    texture.loadFromFile(i_texture_location);

    total_frames = texture.getSize().x / frame_width;
}

void Animation::draw(sf::RenderWindow& i_window)
{
    sprite.setTexture(texture);

    if (0 == reversed)
    {
        sprite.setTextureRect(sf::IntRect(current_frame * frame_width, 0, frame_width, texture.getSize().y));
    }
    else
    {
    
        sprite.setTextureRect(sf::IntRect(frame_width * (1 + current_frame), 0, -frame_width, texture.getSize().y));
    }

    i_window.draw(sprite);
}

void Animation::set_animation_speed(const unsigned short i_animation_speed)
{
    animation_speed =  i_animation_speed;
}

void Animation::set_reversed(const bool i_value)
{
    reversed = i_value;
}

void Animation::set_position(const short i_x, const short i_y)
{
    sprite.setPosition(i_x, i_y);
}

void Animation::set_texture_location(const std::string& i_texture_location)
{
    texture.loadFromFile(i_texture_location);
}

void Animation::update()
{
    while (animation_iterator >= animation_speed)
    {
        animation_iterator -= animation_speed;

        current_frame = (1 + current_frame) % total_frames;
    }

    animation_iterator++;
}

Hero.h

#pragma once
#include <SFML/Graphics.hpp>
#include "Animation.h"
int CELL_SIZE = 85;
class Hero {
    bool crouching=0;
    bool dead=0;
    bool reversed=0;
    bool on_ground=0;
    float horizontal_speed;
    float vertical_speed;
    float x=0;
    float y=0;
    unsigned char jump_timer=0;//при зажатии кнопки прыжка персонаж прыгает выше
    sf::Sprite sprite;
    sf::Texture texture;
    Animation walk_animation = Animation(CELL_SIZE, "Resources/Images/Hero_Walk.png", 1);
public:
    Hero() {
        texture.loadFromFile("Resources/Images/Hero_Idle.png");
        sprite.setTexture(texture);
    }
    void draw(sf::RenderWindow& i_window) {
        sprite.setPosition(round(x), round(y));
        i_window.draw(sprite);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
            sprite.setTextureRect(sf::IntRect(0, 0, texture.getSize().x, texture.getSize().y));
            walk_animation.set_position(round(x), round(y));
            
            walk_animation.draw(i_window);
        
            
        }

    }
    

I have tried to increase the counter of the current frame but that makes the animation disappear from the screen, also trying to refresh the sprite screen clears everything completely


Solution

  • As long as the right arrow is pressed you should cycle between draw and update. This way after every frame is drawn the next will be ready. the fix should be easy: just append a call to update after the draw call. Then the next time you'll enter this function, assuming you have an event polling loop, the next animation should be drawn.