Все статьи Явное ожидание завершения кадра на C++
Игровой цикл с ожиданием завершения кадра
Общая идея состоит в том, чтобы установить интервал между кадрами не менее 16 миллисекунд. Если игра не тормозит, FPS застынет в районе 60 Гц, в противном случае игра будет стараться нарисовать максимально близкое к 60 число кадров, занимая всё процессорное время.
using namespace std::chrono;
// Запрашивает время, прошедшее с последнего кадра, и обновляет lastFrameTime
float GrabDeltaTime(system_clock::time_point &lastFrameTime)
{
auto newTime = system_clock::now();
auto timePassed = duration_cast<milliseconds>(newTime - m_lastTime);
lastFrameTime = newTime;
return 0.001f * float(timePassed.count());
};
// Ожидает до момента времени `lastFrameTime + framePeriod`
void WaitNextFrameTime(const system_clock::time_point &lastFrameTime, const milliseconds &framePeriod)
{
system_clock::time_point nextFrameTime = lastFrameTime + framePeriod;
std::this_thread::sleep_until(nextFrameTime);
}
const milliseconds FRAME_PERIOD(16);
void main()
{
// Инициализация игры.
system_clock::time_point lastFrameTime;
while (window.isOpen())
{
const float dt = GrabDeltaTime(lastFrameTime);
// Обработка событий (handle events)
// Обновление сцены (update)
window.clear(sf::Color::Black);
// Рисование состояния игры в буфер кадра.
window.display();
chronometer.WaitNextFrameTime(lastFrameTime, FRAME_PERIOD);
}
return 0;
}
Оборачиваем работу со временем в класс CChronometer
Вспомогательный класс позволит упростить исчисление промежутков времени — необходимые данные он хранит вокруг себя.
// Класс отвечает за измерение промежутков времени между кадрами
// и за ожидание следующего кадра.
class CChronometer
{
public:
CChronometer();
float GrabDeltaTime();
void WaitNextFrameTime(const std::chrono::milliseconds &framePeriod);
private:
std::chrono::system_clock::time_point m_lastTime;
};
float CChronometer::GrabDeltaTime()
{
auto newTime = system_clock::now();
auto timePassed = duration_cast<milliseconds>(newTime - m_lastTime);
m_lastTime = newTime;
return 0.001f * float(timePassed.count());
};
void CChronometer::WaitNextFrameTime(const milliseconds &framePeriod)
{
system_clock::time_point nextFrameTime = m_lastTime + framePeriod;
std::this_thread::sleep_until(nextFrameTime);
}