c++ 使用SDL 2实现稳定的60 fps

e5nszbig  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(201)

我一直在努力寻找关于如何在使用SDL 2的游戏中实现稳定的60 fps的行业标准的信息,在阅读了一堆文章之后,我迭代了不同的想法,直到我能够在我的游戏中测量60(+-0. 1)fps。
下面是我目前的方法,我正在寻找验证,这是不是完全错误/纠正实际游戏(2D)如何做到这一点。

  1. const float TARGET_FPS = 60.04f;
  2. const float SCREEN_TICKS_PER_FRAME = 1000.0f / static_cast<float>(TARGET_FPS);
  3. ...
  4. class Timer{
  5. public:
  6. Uint64 started_ticks = 0;
  7. Timer()
  8. :started_ticks{SDL_GetPerformanceCounter()}
  9. {}
  10. void restart() {
  11. started_ticks = SDL_GetPerformanceCounter();
  12. }
  13. float get_time() {
  14. return (static_cast<float>(SDL_GetPerformanceCounter() - started_ticks) / static_cast<float>(SDL_GetPerformanceFrequency()) * 1000.0f);
  15. }
  16. };
  17. ...
  18. float extra_time{0};
  19. Timer fps_cap_timer{};
  20. while(game_loop_condition){
  21. fps_cap_timer.restart();
  22. ...
  23. render();
  24. while((fps_cap_timer.get_time() + extra_time) < SCREEN_TICKS_PER_FRAME) {
  25. SDL_Delay(1); // I am aware of the issues with delay on different platforms / OS scheduling
  26. }
  27. if (fps_cap_timer.get_time() < (SCREEN_TICKS_PER_FRAME)) {
  28. extra_time -= SCREEN_TICKS_PER_FRAME - fps_cap_timer.get_time();
  29. }
  30. else {
  31. extra_time += fps_cap_timer.get_time() - SCREEN_TICKS_PER_FRAME;
  32. }
  33. }

字符串
使用这种方法,总是有一点额外的时间在0 - 1 ms之间波动,这导致FPS略低于60,因此我将目标FPS调整为60.04,我得到60±0.1 FPS。
那么.这是真的可行还是我搞砸了什么,应该做更多的阅读的主题?

5rgfhyps

5rgfhyps1#

注意事项:通常不依赖FPS,而是测量自上一帧以来的时间,并将其用作游戏对象移动距离的乘数。
虽然在某些情况下可能需要一个相当精确的FPS,但由于您在每次循环迭代中重新启动计时器,它会漂移。我建议只需向计时器添加固定的持续时间并等待直到时间点发生。仅使用标准库类和函数,它可能看起来像这样:

  1. #include <chrono>
  2. #include <cstdint>
  3. #include <iostream>
  4. #include <thread>
  5. #include <type_traits>
  6. template<std::intmax_t FPS>
  7. class Timer {
  8. public:
  9. // initialize Timer with the current time point:
  10. Timer() : tp{std::chrono::steady_clock::now()} {}
  11. // a fixed duration with a length of 1/FPS seconds
  12. static constexpr std::chrono::duration<double, std::ratio<1, FPS>>
  13. time_between_frames{1};
  14. void sleep() {
  15. // add to the stored time point
  16. tp += time_between_frames;
  17. // and sleep almost until the new time point
  18. std::this_thread::sleep_until(tp - std::chrono::microseconds(100));
  19. // less than 100 microseconds busy wait
  20. while(std::chrono::steady_clock::now() < tp) {}
  21. }
  22. private:
  23. // the time point we'll add to in every loop
  24. std::chrono::time_point<std::chrono::steady_clock,
  25. std::remove_const_t<decltype(time_between_frames)>> tp;
  26. };

字符串
忙碌的等待是为了使FPS尽可能准确,但它会消耗CPU,所以你想让它尽可能短。100µs可能太多了,所以你可以让它更短,甚至删除它,如果你发现没有它的准确性足够好。
然后你的游戏循环将是:

  1. int main() {
  2. // setup ...
  3. Timer<60> fps_cap_timer; // 60 FPS
  4. while(game_loop_condition) {
  5. render();
  6. fps_cap_timer.sleep(); // let it sleep any time remaining
  7. }
  8. }

展开查看全部

相关问题