从精灵表中以 sfml 动画精灵
Posted
技术标签:
【中文标题】从精灵表中以 sfml 动画精灵【英文标题】:Animating sprites in sfml from a sprite sheet 【发布时间】:2019-03-10 08:30:16 【问题描述】:我正在尝试为 sfml 中的精灵制作动画。目前,我可以移动精灵并在朝不同方向移动时更改其图像,但我想在它移动时为其设置动画。我在想可能有一种方法可以使用 sf::Clock 来实现这一点,或者可能有更好的方法。所有精灵都在同一个精灵表上,所以我只需要找到一种方法来根据时间更改 textureRect 的 X 和 Y 坐标,同时在一个方向上移动。如果我遗漏了什么或您有任何问题,我将尽我所能回答。
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();
字符.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();
;
字符.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;
【问题讨论】:
Maverick 的回答是正确的,但如果您不想推出自己的动画类,您可以使用在 SFML 之上构建的 Thor 库:bromeon.ch/libraries/thor 请记住,Thor 非常有限,并且已知会崩溃。维护者不在附近修复它们。 酷,如果 Mavericks 的答案不适合我,我会检查一下,但我相信它会的,谢谢。 @DapperDaniel 嘿,我不知道这是否是正确的询问方式或地点,但我正在尝试完成您在发布之前已经完成的工作(在更改图片)。我试图通过你的代码,但我不明白你是怎么做到的。有什么办法解释吗?我应该发个帖子或其他东西然后在这里链接还是? 【参考方案1】:您需要跟踪动画中的帧(sf::IntRects 列表)。并且在两者之间有某种延迟。更新时,只需在框架中移动并应用矩形。
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 = ⌖
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
;
你可以这样使用:
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);
【讨论】:
谢谢,我会尽快实现。 要在我当前的代码中实现这一点,我是否只需在 if(sf::Keyboard::isKeyPressed) 下添加我需要的帧,这样当我向不同方向移动时它会播放不同的动画?而且animation.update还是会进入主循环或者键盘输入之后? 在场景开始时不添加帧。如果您需要不同的动画,请使用不同的动画对象,并且只在您需要的那个上调用.update()
。
在更新参数中,经过的时间是帧之间的时间还是动画开始的时间,我需要在那里使用 sf::Clock 吗?
elapsed 是从主循环中的 sf::Clock 返回的秒数以上是关于从精灵表中以 sfml 动画精灵的主要内容,如果未能解决你的问题,请参考以下文章