我正在开发一款使用WindowsAPI创建窗口的游戏。但是,目前这个过程占据了我CPU的50%。我正在做的就是使用下面的代码创建窗口和循环:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MSG message = {0};
WNDCLASSEX wcl = {0};
wcl.cbSize = sizeof(wcl);
wcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wcl.lpfnWndProc = WindowProc;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hInstance = hInstance = hInstance;
wcl.hIcon = LoadIcon(0, IDI_APPLICATION);
wcl.hCursor = LoadCursor(0, IDC_ARROW);
wcl.hbrBackground = 0;
wcl.lpszMenuName = 0;
wcl.lpszClassName = "GL2WindowClass";
wcl.hIconSm = 0;
if (!RegisterClassEx(&wcl))
return 0;
hWnd = CreateAppWindow(wcl, "Application");
if (hWnd)
{
if (Init())
{
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
while (true)
{
while (PeekMessage(&message, 0, 0, 0, PM_REMOVE))
{
if (message.message == WM_QUIT)
break;
TranslateMessage(&message);
DispatchMessage(&message);
}
if (message.message == WM_QUIT)
break;
if (hasFocus)
{
elapsedTime = GetElapsedTimeInSeconds();
lastEarth += elapsedTime;
lastUpdate += elapsedTime;
lastFrame += elapsedTime;
lastParticle += elapsedTime;
if(lastUpdate >= (1.0f / 100.0f))
{
Update(lastUpdate);
lastUpdate = 0;
}
if(lastFrame >= (1.0f / 60.0f))
{
UpdateFrameRate(lastFrame);
lastFrame = 0;
Render();
SwapBuffers(hDC);
}
if(lastEarth >= (1.0f / 10.0f))
{
UpdateEarthAnimation();
lastEarth = 0;
}
if(lastParticle >= (1.0f / 30.0f))
{
particleManager->rightBooster->Update();
particleManager->rightBoosterSmoke->Update();
particleManager->leftBooster->Update();
particleManager->leftBoosterSmoke->Update();
particleManager->breakUp->Update();
lastParticle = 0;
}
}
else
{
WaitMessage();
}
}
}
Cleanup();
UnregisterClass(wcl.lpszClassName, hInstance);
}
return static_cast<int>(message.wParam);
}
GetElapsedTimeInSeconds:
float GetElapsedTimeInSeconds()
{
static const int MAX_SAMPLE_COUNT = 50;
static float frameTimes[MAX_SAMPLE_COUNT];
static float timeScale = 0.0f;
static float actualElapsedTimeSec = 0.0f;
static INT64 freq = 0;
static INT64 lastTime = 0;
static int sampleCount = 0;
static bool initialized = false;
INT64 time = 0;
float elapsedTimeSec = 0.0f;
if (!initialized)
{
initialized = true;
QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq));
QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&lastTime));
timeScale = 1.0f / freq;
}
QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&time));
elapsedTimeSec = (time - lastTime) * timeScale;
lastTime = time;
if (fabsf(elapsedTimeSec - actualElapsedTimeSec) < 1.0f)
{
memmove(&frameTimes[1], frameTimes, sizeof(frameTimes) - sizeof(frameTimes[0]));
frameTimes[0] = elapsedTimeSec;
if (sampleCount < MAX_SAMPLE_COUNT)
++sampleCount;
}
actualElapsedTimeSec = 0.0f;
for (int i = 0; i < sampleCount; ++i)
actualElapsedTimeSec += frameTimes[i];
if (sampleCount > 0)
actualElapsedTimeSec /= sampleCount;
return actualElapsedTimeSec;
}
所以,即使我在窗口有焦点时没有画任何东西,它仍然需要50%。我不明白这是如何占用这么多系统资源的。
我做错了吗?
非常感谢任何帮助,谢谢!
答案 0 :(得分:3)
hasfocus从天而降。当它是真的时,你将燃烧100%核心,if()语句中没有任何内容可以让你的程序等待任何事情。睡眠(1)会解决这个问题,但是你打算做什么并不明显。
答案 1 :(得分:1)
您的应用程序在紧凑的循环中运行并且通过不执行任何有用的操作来刻录CPU。您必须在循环中添加Sleep(1)
之类的内容。
您提供的这个示例是一个退化的情况,并不一定要修复。如果你打算用这个做游戏,那么你将把帧更新和渲染功能放到循环中,它将做一些有用的“东西”。在这种情况下,您不希望“睡眠”任何周期。
如果我是你,我不会从头开始制作游戏,并会寻找一些游戏引擎。市场上有很多高质量的开源和闭源免费游戏引擎。或者至少寻找一些简单的游戏骨架,它们提供基本的东西,比如消息循环和双缓冲窗口绘图设置。
答案 2 :(得分:1)
添加其他答案......
你需要以某种方式限制你的游戏循环。如果没有消息,PeekMessage会立即返回,因此您只需尽可能快地循环,消耗100%的CPU核心。假设你有双核PC,你可能会看到50%。
不要执行Sleep()以避免消耗100%的CPU周期,而是在每个循环开始时调用MsgWaitForMultipleObjects,传入零句柄,传递一个小的超时,即帧之间的最小间隔。每次返回时,因为超时已经过去,或者因为有消息需要处理。如果有消息,处理它们(全部)然后,无论哪种方式,然后处理游戏OnNextFrame / Repaint循环。使用UpdateWindow而不是等待发布WM_PAINT。