我的精灵动画在 C++ 中使用 SFML 的帧速率和增量时间

问题描述 投票:0回答:1

我正在使用 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 来定义增量时间。我不知道如何在我的代码中做到这一点。我该怎么办呢? 我不知道如何继续

c++ animation 2d sfml frame-rate
1个回答
0
投票

为了使动画帧速率独立,您可以动态增加动画帧索引。这可以通过使用

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.