我正在使用 C++ 和 SFML 库研究 2D 动画。我使用 png 精灵表。我作为起点编写的代码如下:
#include <SFML/Graphics.hpp>
#include <iostream>
int main(int argc, char** argv)
{
// creates a window on the screen that is 800 by 600
sf::RenderWindow window(sf::VideoMode(800, 600), "Framerate indipendent!", sf::Style::Default);
window.setFramerateLimit(20); // this is how I limit the max frame change speed of the
// spritesheet
sf::Texture t1;
t1.loadFromFile("./res/professor.png"); // 576 x 256 pixel
sf::Sprite sprite;
sprite.setTexture(t1);
// starting animation row 4 (y = 192), column 2 (x = 64).
sprite.setTextureRect(sf::IntRect(64, 192, 64, 64));
// frame (o sprite) current
int f = 0; // idle
// the main game loop, exits if someone closes the window
while (window.isOpen() && !sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
// creates an event object, events include keyboard presses, etc...
sf::Event event;
// loop that checks for events
while (window.pollEvent(event))
{
// checks if window is closed
if (event.type == sf::Event::Closed)
window.close();
}
f++;
if (f > 8) f = 1;
std::cout << f << std::endl;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
// key D
sprite.setTextureRect(sf::IntRect(f % 8 * 64, 64 * 3, 64, 64));
// move sprite
sprite.move(3, 0);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
// key A
sprite.setTextureRect(sf::IntRect(f % 8 * 64, 64, 64, 64));
// move sprite
sprite.move(-3, 0);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
// key W
sprite.setTextureRect(sf::IntRect(f % 8 * 64, 0, 64, 64));
// move sprite
sprite.move(0, -3);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
// key S
sprite.setTextureRect(sf::IntRect(f % 8 * 64, 64 * 2, 64, 64));
// move sprite
sprite.move(0, 3);
}
// Draw
// clears the screen
window.clear(sf::Color::White);
// Draw everything
window.draw(sprite);
// displays everything on the video card to the monitor
window.display();
}
return 0;
}
所以动画很好,因为我对显卡的 fps 设置了限制。现在我想让动画速度独立于显卡 fps(不使用 window.setFramerateLimit(20))。我需要使用 sf::Clock 和 sf::Time 来定义增量时间。我不知道如何在我的代码中做到这一点。我该怎么办呢? 我不知道如何继续
为了使动画帧速率独立,您可以动态增加动画帧索引。这可以通过使用
sf::Clock
来完成。
这是来自 SFML 的关于增量时间的指南。
唯一需要进行的更改:
int f
更改为 float f
以提高准确性f
增加 sf::Clock::restart (elapsed time)
int
以进行整数数学计算#include <SFML/Graphics.hpp>
#include <iostream>
#include <cmath>
int main(int argc, char** argv)
{
// creates a window on the screen that is 800 by 600
sf::RenderWindow window(sf::VideoMode(800, 600), "Framerate indipendent!", sf::Style::Default);
window.setFramerateLimit(20); // this is how I limit the max frame change speed of the
// spritesheet
sf::Texture t1;
t1.loadFromFile("./res/professor.png"); // 576 x 256 pixel
sf::Sprite sprite;
sprite.setTexture(t1);
// starting animation row 4 (y = 192), column 2 (x = 64).
sprite.setTextureRect(sf::IntRect(64, 192, 64, 64));
// frame (o sprite) current
float f = 0.0f; // idle
// clock that counts the elapsed time
sf::Clock clock;
// the main game loop, exits if someone closes the window
while (window.isOpen() && !sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
// creates an event object, events include keyboard presses, etc...
sf::Event event;
// loop that checks for events
while (window.pollEvent(event))
{
// checks if window is closed
if (event.type == sf::Event::Closed)
window.close();
}
sf::Time elapsed = clock.restart();
// multiply by 20, to keep 20 images per second
f += elapsed.as_seconds() * 20.0f;
f = std::fmod(f, 8.0f);
std::cout << f << std::endl;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
// key D
sprite.setTextureRect(sf::IntRect(static_cast<int>(f) * 64, 64 * 3, 64, 64));
// move sprite
sprite.move(3, 0);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
// key A
sprite.setTextureRect(sf::IntRect(static_cast<int>(f) * 64, 64, 64, 64));
// move sprite
sprite.move(-3, 0);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
// key W
sprite.setTextureRect(sf::IntRect(static_cast<int>(f) * 64, 0, 64, 64));
// move sprite
sprite.move(0, -3);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
// key S
sprite.setTextureRect(sf::IntRect(static_cast<int>(f) * 64, 64 * 2, 64, 64));
// move sprite
sprite.move(0, 3);
}
// Draw
// clears the screen
window.clear(sf::Color::White);
// Draw everything
window.draw(sprite);
// displays everything on the video card to the monitor
window.display();
}
return 0;
}