【问题标题】:My SFML/C++ program is working as expected but how to make movement slow?我的 SFML/C++ 程序按预期工作,但如何让移动变慢?
【发布时间】:2023-03-31 22:26:02
【问题描述】:

我作为我们的玩家做了一个圆圈并设置了重力,但它的工作速度非常快,我什至看不到。我认为它必须与 sf::time 或 sf::clock 做一些事情,但如何?我实际上并没有得到这两个,所以任何代码示例和解释都将不胜感激。这是我的代码:-

#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML works!");
    sf::CircleShape shape(20);
    shape.setFillColor(sf::Color::White);
    shape.setPosition(380, 550);
    shape.setOutlineColor(sf::Color::Green);
    shape.setOutlineThickness(3);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                {
                    shape.move(0, -100);
                }
                if(event.KeyReleased)
                {
                    if(event.key.code == sf::Keyboard::Up)
                    {
                    int x[] = { 10, 10, 10, 10, 10};
                    for (int y = 0; y <= 4; y++)
                    {
                        shape.move(0, x[y]);
                    }

                    }
                }

        }

        window.clear(sf::Color::Black);
        window.draw(shape);
        window.display();
    }

    return 0;
}

【问题讨论】:

  • s = v * t;您缺乏任何时间概念,因此计算机正在尽可能快地移动对象。您必须测量每次迭代所花费的时间,然后将该(增量)时间乘以您的速度。
  • @Paranaix 是正确的。您的计算机正在尽可能快地检查 Up 按键。因此,您需要实现某种帧速率。我对 SFML 中的计时不太熟悉,但根据时钟的精度,您可以执行 if(clock() % 120) == 0) 之类的按键检查​​。这样一来,您只需每 120 个单位时间进行一次检查(我认为通常是毫秒?)

标签: c++ time clock sfml gravity


【解决方案1】:

请记住,您的程序可能每秒运行数百帧,因此当您按下键盘上的向上按钮时,它会将对象每帧移动 -100 像素,这绝对不是您想要的。

那么你如何解决这个问题?你需要包括时间的概念。我们通过使用时间步来查看自调用最后一帧以来已经过去了多少时间。

这是一个简短的示例代码,展示了如何构建这个时间步(有许多不同的方式,每种方式各有优缺点)。

sf::Time timePerFrame = sf::seconds(1.0f / 60.0f); // 60 frames per second
sf::Clock deltaClock;  // This will track how much time has past since the last frame
sf::Time timeSinceLastUpdate = sf::Time::Zero;

while (m_Window.isOpen())
{
    sf::Time deltaTime = deltaClock.restart();  // Restart returns the time since the last restart call
    timeSinceLastUpdate += deltaTime;

    while (timeSinceLastUpdate >= timePerFrame)
    {
        timeSinceLastUpdate -= timePerFrame;

        ProcessInput();
        Update(timePerFrame);  // Notice how I pass the time per frame to the update function
    }

    Render();
}

然后在您的更新代码中,您只需将要移动的距离乘以您传递给更新函数的对象 timePerFrame(确保使用sf::Time::asSeconds())。例如,您的代码看起来像这样

shape.move(0, -100 * timePerFrame.asSeconds());

如果您正在寻找有关时间步如何工作的深入解释,我会推荐这篇文章http://gafferongames.com/game-physics/fix-your-timestep/

【讨论】:

    【解决方案2】:

    正如@Zereo 所回应的,但有一个简化的版本:你可以让 SFML 来处理,而不是你处理帧速率:

        window.setFramerateLimit(60);
    

    在创建窗口后添加此行,SFML 会将您的帧限制为 60/s。

    【讨论】:

    • 这有一个潜在的问题,因为 60fps 只是一个上限。因此,例如,如果应用程序只能达到 30fps,则动作将减慢到一半。
    • 正如 Kaathe 所说,使用 window.SetFramerateLimit(60);给你很少的控制和实现,除非他们最近改变了它使用 sf::Sleep 是臭名昭著的不准确github.com/LaurentGomila/SFML/wiki/…。所以我强烈建议不要使用它。还想补充一点,即使您确实使用了它,它也无法解决手头的问题,因为它无法让您了解自上一帧以来已经过去了多少时间。
    • 那么限制帧数一点都不好?哪怕是个小项目?
    • 如果通过限制帧你的意思是使用 window.setFramerateLimit() 那么正确我不建议特别使用它,因为它很容易设置你自己的并且对它有更多的控制。对于小玩具项目,我想这会很好,但请确保您记得获取自上一帧以来已经过去的时间。但是对于任何甚至有点严重的事情,由于已经说明的原因,您肯定不想使用它。
    猜你喜欢
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    • 2015-03-09
    • 2018-03-21
    相关资源
    最近更新 更多