Простая программа c++ SFML высокая загрузка ЦП

в настоящее время я работаю над платформером и пытаюсь реализовать timestep, но для ограничений частоты кадров больше 60 использование процессора увеличивается с 1% до 25% и более.

Я сделал эту минимальную программу, чтобы продемонстрировать проблему. В коде есть два комментария (строки 10-13, строки 26-30), которые описывают проблему и то, что я тестировал.

обратите внимание, что материал FPS не имеет отношения к проблеме (я думаю).

Я попытался сохранить код коротким и просто:

#include <memory>
#include <sstream>
#include <iomanip>
#include <SFMLGraphics.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;
}

Я не хочу использовать setFramerateLimit () SFML, но моя собственная реализация со сном, потому что я буду использовать данные fps для обновления моей физики и прочее.

есть ли логическая ошибка в моем коде? Я не вижу его, поскольку он работает с предельной частотой, например 60 (или меньше). Это потому что у меня монитор 60 Гц?

PS: использование окна SFML - >setVerticalSync () не изменяет результаты

2 ответов


Я ответил на другой аналогичный вопрос С ответ.

дело в том, что это не совсем помогает вам с использованием процессора, но я попробовал ваш код, и он отлично работает под 1% cpu при 120 FPS (и многое другое). Когда вы делаете игру или интерактивный носитель с "игровым циклом", вы не хотите терять производительность, спя, вы хотите использовать столько времени процессора, сколько компьютер может дать вам. Вместо сна вы можете обрабатывать другие данные, например загрузка материала, алгоритм поиска пути и т. д., или просто не ставьте ограничений на рендеринг.

Я предоставить некоторые полезные ссылки и код, вот он:


аналогичный вопрос: Движение без ограничения частоты кадров c++ SFML.

что вам действительно нужно, это фиксированный шаг по времени. Взгляните на игру SFML книги исходный код. Вот интересный фрагмент из 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();
}

Если это не совсем то, что вы хотите, увидеть "исправить вашу выместив!" который сам Лоран Гомила связал на форуме SFML.


Я предлагаю использовать предел 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))

надеюсь, что это поможет :)