You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++ raylib游戏中实现高效的独立固定帧率更新循环?

固定间隔游戏更新循环的高效实现(Raylib + C++ Windows环境)

问题背景

我用C++结合Raylib开发游戏,运行环境为Windows x64,通过Eclipse搭配MinGW编译。

常规Raylib游戏循环示例如下:

int main()
{
    InitWindow(800, 600, ("Window Title").c_str());
    SetWindowState(FLAG_VSYNC_HINT);
    
    while (!WindowShouldClose())
    {
        Update(); // 游戏更新逻辑
        
        BeginDrawing();
        
        ClearBackground((Color){0, 0, 0, 255});
        
        Draw(); // 游戏绘制逻辑
        
        EndDrawing();
    }
}

这种写法存在明显弊端:开启VSYNC后渲染帧率与显示器刷新率绑定,但更新逻辑和渲染逻辑在同一循环内,导致更新帧率也被限制在刷新率上。不同用户的显示器刷新率(60Hz、50Hz、120Hz等)会让游戏运行速度差异极大,不符合需求。

我希望更新逻辑始终以16ms间隔(约62.5FPS)独立运行,渲染逻辑保持VSYNC同步。尝试用多线程实现后,代码能正常运行,但更新线程CPU占用极高(4核系统占25%)。已知sleep和std::thread::sleep_for精度不足,且不想用基于deltaTime的插值方案,求高效的固定间隔独立更新循环实现方式。

我的多线程尝试代码:

std::thread ULT(scr_run_updateloop); // 启动更新线程

while (!WindowShouldClose())
{
    BeginDrawing();
        
    ClearBackground((Color){0, 0, 0, 255});
        
    Draw(); // 绘制逻辑
        
    EndDrawing();
}

更新线程函数:

void scr_run_updateloop()
{
    auto time_current = chrono::steady_clock::now();
    auto time_last = time_current;
    uint64_t time_d;
    
    while (true)
    {
        time_current = chrono::steady_clock::now();
        time_d = duration_cast<milliseconds>(time_current - time_last).count();

        if (time_d >= 16) // 16ms间隔
        {
            Update();
            time_last = time_current;
        }
    }
}

高效解决方案

方案1:Windows原生Waitable Timer API

Windows的Waitable Timer可以实现高精度定时触发,线程等待期间会进入休眠状态,几乎不占用CPU。

#include <windows.h>
#include <chrono>
#include <atomic>

std::atomic<bool> shouldExit = false;

void scr_run_updateloop()
{
    HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
    if (!hTimer) return;

    // 设置定时参数:立即启动,周期16ms
    LARGE_INTEGER liDueTime;
    liDueTime.QuadPart = 0;
    SetWaitableTimer(hTimer, &liDueTime, 16, NULL, NULL, FALSE);

    while (!shouldExit)
    {
        // 等待定时器触发,线程休眠不占用CPU
        WaitForSingleObject(hTimer, INFINITE);
        Update(); // 执行更新逻辑
    }

    CloseHandle(hTimer);
}

int main()
{
    InitWindow(800, 600, "Window Title");
    SetWindowState(FLAG_VSYNC_HINT);
    
    std::thread updateThread(scr_run_updateloop);

    while (!WindowShouldClose())
    {
        BeginDrawing();
        ClearBackground(BLACK);
        Draw();
        EndDrawing();
    }

    // 安全终止更新线程
    shouldExit = true;
    // 手动触发定时器,让线程从等待状态退出
    SetWaitableTimer(reinterpret_cast<HANDLE>(updateThread.native_handle()), NULL, 0, NULL, NULL, FALSE);
    updateThread.join();
    
    CloseWindow();
    return 0;
}

说明:

  • Waitable Timer精度可达毫秒级,完全满足16ms间隔需求
  • 线程等待时处于休眠状态,CPU占用极低
  • 通过shouldExit原子变量实现线程安全退出,避免主线程退出后更新线程残留

方案2:std::this_thread::sleep_until 精准休眠

利用std::chrono计算下一次更新的时间点,用sleep_until休眠到该时间点,相比sleep_for能自动修正误差,精度更高。

#include <chrono>
#include <thread>
#include <atomic>

std::atomic<bool> shouldExit = false;

void scr_run_updateloop()
{
    using namespace std::chrono;
    auto nextUpdateTime = steady_clock::now();
    const auto updateInterval = milliseconds(16);

    while (!shouldExit)
    {
        nextUpdateTime += updateInterval;
        // 休眠到下一次更新时间点
        std::this_thread::sleep_until(nextUpdateTime);
        Update();
    }
}

int main()
{
    InitWindow(800, 600, "Window Title");
    SetWindowState(FLAG_VSYNC_HINT);
    
    std::thread updateThread(scr_run_updateloop);

    while (!WindowShouldClose())
    {
        BeginDrawing();
        ClearBackground(BLACK);
        Draw();
        EndDrawing();
    }

    shouldExit = true;
    updateThread.join();
    
    CloseWindow();
    return 0;
}

说明:

  • sleep_until直接休眠到目标时间点,能累积修正每次休眠的微小误差,保证长期间隔稳定
  • Windows下该方法精度一般在1ms左右,足够满足需求
  • 同样通过原子变量实现线程安全退出

关键注意事项

  1. 线程同步:更新线程和渲染线程共享的游戏数据(如实体位置、游戏状态)必须用std::mutex或原子变量保护,避免数据竞争导致异常。
  2. Raylib API线程安全:Raylib的渲染相关API(如Draw*系列)只能在主线程调用;输入检测API(如IsKeyPressed)建议放在主线程,将输入状态传递给更新线程,避免跨线程调用问题。

内容的提问来源于stack exchange,提问作者DrZ214

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:45:04