Простая C ++ SFML программа с высокой загрузкой процессора

В настоящее время я работаю над платформером и пытаюсь реализовать временной шаг, но для ограничений частоты кадров более 60 загрузка ЦП возрастает с 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 (), но мою собственную реализацию со сном, потому что я буду использовать данные fps для обновления своей физики и прочего.

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

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

6

Решение

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

Дело в том, что это не совсем помогает вам использовать процессор, но я попробовал ваш код, и он работает нормально при загрузке процессора 1% при 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.

7

Другие решения

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

Надеюсь это поможет 🙂

1

По вопросам рекламы [email protected]