WIN32游戏循环很慢,无法处理60HZ或30HZ。该怎么办?

问题描述 投票:0回答:1

我只是想学习编程一些东西,游戏循环就是其中之一。

这个游戏循环仅处理 Windows 消息,但它甚至无法处理 30 fps。

如果每个循环只处理一次消息,用 IF 替换 WHILE,情况也是如此。

我使用 QueryPerformanceCounter() 函数来获取工作完成之前和之后的 100 纳秒刻度数,减去它们即可得到所用时间。循环时间为 100ns * 166666 * 2 = 0.0333332s。

如果等待时间为正,则设置布尔值“timeExceeded”,表示使用的时间超过预期的循环时间。

该怎么办?

#include <Windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    // windows class information
    static const wchar_t class_name[] = L"Test";
    WNDCLASS wc{ };
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = class_name;
    if (!RegisterClassW(&wc))
        return 0;

    // Get correct windows size based on disered client area
    RECT client_rect;
    client_rect.left = 0;
    client_rect.top = 0;
    client_rect.right = 800;
    client_rect.bottom = 600;
    if (!AdjustWindowRect(&client_rect, WS_OVERLAPPEDWINDOW, FALSE))
        return 0;

    // create windows
    HWND hwnd = CreateWindowEx(
        WS_EX_OVERLAPPEDWINDOW, class_name, L"Test",
        WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED,
        100, 100, -client_rect.left + client_rect.right, -client_rect.top + client_rect.bottom,
        0, 0, hInstance, 0
    );
    if (hwnd == 0)
        return 0;



    // Show Window
    ShowWindow(hwnd, SW_SHOWNORMAL);

    // Timer & setup
    LARGE_INTEGER frequency;
    if (!QueryPerformanceFrequency(&frequency))
        return 0;
    if (frequency.QuadPart != 10000000LL)
        return 0;

    HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
    if (hTimer == 0)
        return 0;


    // timer data
    LARGE_INTEGER start_time;
    LARGE_INTEGER end_time;
    LARGE_INTEGER rest_time;
    LARGE_INTEGER loop_time;
    loop_time.QuadPart = -166666LL*2;   // loop time

    bool timeExceeded = false;      // does time exceeds loop time


    // message loop data
    MSG msg = { };
    bool running = true;

    while (running)
    {
        // measure time
        if (!QueryPerformanceCounter(&start_time))
            break;

        // process messages
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                running = false;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // other work

        // Get elapsed time and wait for 30hz - elapsed time
        if (!QueryPerformanceCounter(&end_time))
            break;

        rest_time.QuadPart = loop_time.QuadPart + (end_time.QuadPart - start_time.QuadPart);
        if (rest_time.QuadPart >= 0)
        {
            timeExceeded = true;
            continue;
        }
        if (!SetWaitableTimer(hTimer, &rest_time, 0, 0, 0, 0))
            break;

        if (WaitForSingleObject(hTimer, INFINITE) != 0)
            break;
    }

    // clean up
    CloseHandle(hTimer);
    
    return 0;
}



LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
c++ c winapi timing game-loop
1个回答
0
投票

但是,您需要一个交换缓冲区/交换链来很好地处理您的窗口并进行完全自定义,这取决于您处理的API,OpenGL有它自己的方式,directX12有它自己的方式,甚至是SFML提出一个简单的 2D 图形缓冲系统。

但是从我在你的代码中看到的没有图形API,你需要为窗口设置一个缓冲系统(就像我所说的交换链或交换缓冲区),然后考虑测试窗口为我们提供了多少帧第二个

© www.soinside.com 2019 - 2024. All rights reserved.