Animating sprites in sfml from a sprite sheet

时光总嘲笑我的痴心妄想 提交于 2019-12-11 17:25:07

问题


I am trying to animate a sprite in sfml. At the moment I am able to move the sprite and change it's image when moving in a different direction, but I want to animate it while it is moving. I am thinking that there might be a way to accomplish this with sf::Clock or there might be a better way. All sprites are on the same sprite sheet so I just need to find a way to change the X and Y coordinates of the textureRect based on a time while moving in a direction. If I am missing something or you have any questions, I will answer to the best of my ability.

main.cpp

#include <iostream>
#include <SFML/Graphics.hpp>
#include "Character.hpp"

int main() {
    sf::RenderWindow window(sf::VideoMode(5000, 5000), "Awesome Game" );
    Character Boi("SpritesBoi.png", 0, 0, 5, 100);
    sf::Sprite BoiSprite = Boi.getSprite();
    Boi.SheetX = 0;
    Boi.SheetY = 48;

    while (window.isOpen()){

        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event)){
            // "close requested" event: we close the window
            if (event.type == sf::Event::Closed){
                window.close();
            }
        }

        Boi.Move();
        BoiSprite.setTextureRect(sf::IntRect(Boi.SheetX, Boi.SheetY, 110, 150));
        BoiSprite.setPosition(Boi.x_pos, Boi.y_pos);
        window.clear(sf::Color(255, 255, 255));
        window.draw(BoiSprite);
        window.display();
    }

}

Character.hpp

#ifndef Character_hpp
#define Character_hpp

#include <stdio.h>
#include <SFML/Graphics.hpp>
#endif /* Character_hpp */

class Character{
public:
    int health;
    int speed;
    int x_pos;
    int y_pos;
    int SheetX;
    int SheetY;
    sf::Texture texture;
    sf::Sprite sprite;

    Character(std::string image, int xlocation, int ylocation, int s, int h){
        health = h;
        speed = s;
        x_pos = xlocation;
        y_pos = ylocation;
        texture.loadFromFile(image);
    }
    sf::Sprite getSprite() {
        sprite.setTexture(texture);
        sprite.setPosition(x_pos, y_pos);
        sprite.setTextureRect(sf::IntRect(SheetX, SheetY, 110, 150));
        return sprite;
    }

    void Move();

};

Character.cpp

#include "Character.hpp"
#include <iostream>
void Character::Move(){



    //Up
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
        SheetX = 0;
        SheetY = 192;
        y_pos = y_pos - 1;
        Up = true;

    }
    //Down
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
        SheetX = 0;
        SheetY = 48;
        y_pos = y_pos + 1;
        Down = false;

    }
    //Left
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
        SheetX = 0;
        SheetY = 480;
        x_pos = x_pos - 1;
        Left = true;

    }
    //Right
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
        SheetX = 0;
        SheetY = 339;
        x_pos = x_pos + 1;
        Right = true;

    }
    //Up Right
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) and sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
        SheetX = 334;
        SheetY = 490;

    }
    //Up Left
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) and sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
        SheetX = 333;
        SheetY = 340;
    }
    //Down Right
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) and sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
        SheetX = 334;
        SheetY = 48;
    }
    //Down Left
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) and sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
        SheetX = 334;
        SheetY = 191;
    }

}

回答1:


You need to keep track of the frames in the animation (list of sf::IntRects). And have some sort of delay inbetween. On update, simply move through the frames and apply the rectangle.

struct Frame {
   sf::IntRect rect;
   double duration; // in seconds
};

class Animation {
   std::vector<Frame> frames;
   double totalLength;
   double totalProgress;
   sf::Sprite *target;
   public:
     Animation(sf::Sprite& target) { 
       this->target = &target;
       totalProgress = 0.0;
     }

     void addFrame(Frame&& frame) {
       frames.push_back(std::move(frame)); 
       totalLength += frame.duration; 
     }

     void update(double elapsed) {
        totalProgress += elapsed;
        double progress = totalProgress;
        for(auto frame : frames) {
           progress -= (*frame).duration;  

          if (progress <= 0.0 || &(*frame) == &frames.back())
          {
               target->setTextureRect((*frame).rect);  
               break; // we found our frame
          }
     }
};

You can use like so:

sf::Sprite myCharacter;
// Load the image...
Animation animation(myCharacter);
animation.addFrame({sf::IntRect(x,y,w,h), 0.1});
// do this for as many frames as you need

// In your main loop:
animation.update(elapsed);
window.draw(myCharacter);


来源:https://stackoverflow.com/questions/52655335/animating-sprites-in-sfml-from-a-sprite-sheet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!