我只是想学习编程一些东西,游戏循环就是其中之一。
这个游戏循环仅处理 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);
}
但是,您需要一个交换缓冲区/交换链来很好地处理您的窗口并进行完全自定义,这取决于您处理的API,OpenGL有它自己的方式,directX12有它自己的方式,甚至是SFML提出一个简单的 2D 图形缓冲系统。
但是从我在你的代码中看到的没有图形API,你需要为窗口设置一个缓冲系统(就像我所说的交换链或交换缓冲区),然后考虑测试窗口为我们提供了多少帧第二个