简单的C++ SFML程序CPU使用率高

9
我正在制作一个平台游戏,并尝试实现时间步长,但对于帧速率限制大于60的情况,CPU使用率会从1%上升到25%甚至更高。
我创建了这个最小程序来演示问题。代码中有两个注释(第10-13行,第26-30行),描述了问题以及我所测试的内容。
请注意,FPS部分与问题无关(我认为)。
我尝试保持代码简短和简单:
#include <memory>
#include <sstream>
#include <iomanip>
#include <SFML\Graphics.hpp>

int main() {
  // Window
  std::shared_ptr<sf::RenderWindow> window;
  window = std::make_shared<sf::RenderWindow>(sf::VideoMode(640, 480, 32), "Test", sf::Style::Close);
  /*
  When I use the setFramerateLimit() function below, the CPU usage is only 1% instead of 25%+
  (And only if I set the limit to 60 or less. For example 120 increases CPU usage to 25%+ again.)
  */
  //window->setFramerateLimit(60);

  // FPS text
  sf::Font font;
  font.loadFromFile("font.ttf");
  sf::Text fpsText("", font, 30);
  fpsText.setColor(sf::Color(0, 0, 0));

  // FPS
  float fps;
  sf::Clock fpsTimer;
  sf::Time fpsElapsedTime;
  /*
  When I set framerateLimit to 60 (or anything less than 60) 
  instead of 120, CPU usage goes down to 1%.
  When the limit is greater, in this case 120, CPU usage is 25%+
  */
  unsigned int framerateLimit = 120;
  sf::Time fpsStep = sf::milliseconds(1000 / framerateLimit);
  sf::Time fpsSleep;
  fpsTimer.restart();

  while (window->isOpen()) {
    // Update timer
    fpsElapsedTime = fpsTimer.restart();
    fps = 1000.0f / fpsElapsedTime.asMilliseconds();

    // Update FPS text
    std::stringstream ss;
    ss << "FPS: " << std::fixed << std::setprecision(0) << fps;
    fpsText.setString(ss.str());

    // Get events
    sf::Event evt;
    while (window->pollEvent(evt)) {
      switch (evt.type) {
      case sf::Event::Closed:
        window->close();
        break;
      default:
        break;
      }
    }

    // Draw
    window->clear(sf::Color(255, 255, 255));
    window->draw(fpsText);
    window->display();

    // Sleep
    fpsSleep = fpsStep - fpsTimer.getElapsedTime();
    if (fpsSleep.asMilliseconds() > 0) {
      sf::sleep(fpsSleep);
    }

  }

  return 0;
}

我不想使用SFML的setFramerateLimit(),而是用自己的sleep实现,因为我将使用fps数据来更新我的物理和其他内容。

我的代码中有逻辑错误吗?我没有看到它,因为它可以在帧率限制为60(或更低)的情况下工作。这是因为我有一个60 Hz的显示器吗?

PS:使用SFML的window->setVerticalSync()也不会改变结果。

2个回答

7

我在另一个类似的问题中回答了这个答案

问题是,它并没有确切地帮助您解决CPU使用率问题,但是我尝试了您的代码,并且在120 FPS(以及更高速度)下,CPU使用率低于1%。当您制作游戏或交互式媒体时,您不希望通过休眠来失去性能,而是要尽可能利用计算机可以提供给您的CPU时间。您可以处理其他数据,例如加载内容、路径查找算法等,或者只是不限制渲染。

我提供了一些有用的链接和代码,这里是:


Similar question: Movement Without Framerate Limit C++ SFML.

What you really need is fixed time step. Take a look at the SFML Game development book source code. Here's the interesting snippet from Application.cpp:

const sf::Time Game::TimePerFrame = sf::seconds(1.f/60.f);

// ...

sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
while (mWindow.isOpen())
{
    sf::Time elapsedTime = clock.restart();
    timeSinceLastUpdate += elapsedTime;
    while (timeSinceLastUpdate > TimePerFrame)
    {
        timeSinceLastUpdate -= TimePerFrame;

        processEvents();
        update(TimePerFrame);

    }

    updateStatistics(elapsedTime);
    render();
}

If this is not really what you want, see "Fix your timestep!" which Laurent Gomila himself linked in the SFML forum.


谢谢你!(回复晚了很抱歉)。关于你的代码,我有一个问题:我理解得对吗,更新函数现在使用固定时间步长,但渲染没有帧速率限制?如果是这样,那正是我想要的。 - A. D.
这正是它正在做的事情。 - Emile Bergeron

1
我建议使用setFrameRate限制,因为它在SFML中本地实现,并且效果会更好。 要获取经过的时间,您必须执行:
fpsElapsedTime = fpsTimer.getElapsedTime();

如果我要实现类似的东西,我会这样做:
/* in the main loop */
fpsElapsedTime = fpsTimer.getElapsedTime();
if(fpsElapsedTime.asMillisecond() >= (1000/framerateLimit))
{
   fpsTimer.restart();
  // All your content
}

另外,使用sf::Color::White或sf::Color::Black代替(sf::Color(255,255,255))。

希望这有所帮助 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接