Help with Windows game loop...

Started by
6 comments, last by Solias 16 years, 5 months ago
Hello everyone! I got this loop from some tutorial:

	do
	{
		/* Peek messages */
		if (PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		/* Process logic */
		processLogic();

		/* Render screen */
		renderScreen();
	}
	while (msg.message != WM_QUIT);

It doesn't seem to ever get to processLogic; it gets stuck in PeekMessage, even though I specified PM_NOYIELD... How do you guys implement game loops with pure Windows API? Thanks! (Bonus question for an extra cookie: How do you do timers in Win16?)
Advertisement
I always use something like:
if(Initialize()){  while(true)  {    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))    {      if(msg.message == WM_QUIT){ break; }      TranslateMessage(&msg);      DispatchMessage(&msg);    }      ProcessLogic();      RenderScreen();  }    Shutdown();}


For timing you could use GetTickCount() or QueryPerformanceCounter().
You should empty the message queue each time, not just handle 1 message. Otherwise, you may find messages come in more quickly than you can empty them, since you're doing a full render and update for each one.
My way of doing it in my 2d engine, MsgLoop is a function and message is passed to it
int MsgLoop(UINT message, WPARAM wParam, LPARAM lParam) {while(message != WM_QUIT) {    while(PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {      //process all messages so a que wont build up      TranslateMessage(&msg);      DispatchMessage(&msg);    }      ProcessLogic();    RenderScreen();}return message.wParam;}


Could contain some erros, im at school and wrote it out of my head, I'll post my loop again when I'm home

you could add a way to get the time used to go through the entire loop and add this variable to the ProcessLogic() function, so you won't call ProcessLogic 250 times when your refreshrate is 60.
Those two loops you guys showed... Here's the problem with them; they work correctly - but RenderScreen() doesn't do anything. As in, it gets called, I put MessageBoxes before and after the parts that do the drawing and they pop up on every frame, yet nothing gets drawn?

I put a call to that same function under the WM_PAINT message handler and guess what, it draws there... Why? Do you know? Maybe it only allows me to draw on WM_PAINT? Why would that be?

Thanks y'all!

P.S: MadMax1992, there doesn't seem a way to do the time thing under Win16... I'll wait for that book I bought to see if it says anything about that.

[edit]
Okay, here's the problem:
"An application should not call BeginPaint except in response to a WM_PAINT message."

No wonder... So how am I supposed to do RenderScreen in my main loop? :/
Thanks!
[/edit]

[edit2]
Okay, I'm using timers now and it works like a charm... But I see no one using that method (SetTimer, WM_TIMER, etc.), is there a drawback to using it?
[/edit2]

[Edited by - Leo28C on November 21, 2007 3:28:35 PM]
To be honest, I haven't got an idea what win16 is. I'm back from school, so here's my messageloop:

int d3dApp::MsgLoop(){	QueryPerformanceFrequency(&timerFreq);	MSG msg;	ZeroMemory(&msg, sizeof(msg));	//message loop	while (msg.message != WM_QUIT)	{		while (PeekMessage(&msg,0,0,0,PM_REMOVE)) {			//translate dispatch message			TranslateMessage(&msg);			DispatchMessage(&msg);		}		QueryPerformanceCounter(&timeStart);		lastElaspedFrame = lastElaspedFrame + anim_rate;		processLogic(&lastElaspedFrame, &frameDuration);		renderScreen();		anim_rate = (((float)timeEnd.QuadPart - (float)timeStart.QuadPart) / timerFreq.QuadPart);	}	CleanUpDirect3D();		return (int) msg.wParam;}//processlogic should look something like thisvoid processLogic(float lastElaspedFrame, float frameDuration){	if (lastElaspedFrame < frameDuration)	{		return;	}	lastElaspedFrame = 0;	//do stuff with your graphics}


Im not sure if the timer-technique you use has any drawbacks. I wonder what the problem is with your processlogic function, could you perhaps post the entire function here so we can have a look at it?
oh, forgot to mention. If you want to have that WM_PAINT thing fixed:

if (msg.message == WM_PAINT) {      BeginPaint();}
Quote:Original post by Leo28C
[edit2]
Okay, I'm using timers now and it works like a charm... But I see no one using that method (SetTimer, WM_TIMER, etc.), is there a drawback to using it?
[/edit2]


I think those examples you are seeing probably aren't using GDI to do the display. Using OGL or D3D, you just redraw each frame instead of responding to display events.

If you really wanted to, you could use invalidate in your game loop to trigger a display event to handle. I'm not clear that this would be better than using timers though.

This topic is closed to new replies.

Advertisement