Sign in to follow this  
zappernapper

problem w/ my logic? win32 api

Recommended Posts

ok, i'm trying to put together a memory type game and the way i'd like it to work is you first select a tile, it turns over. then you select the second tile, that one turns over. the computer checks to see if they are a match, if so the tiles remain turned over and a counter is incremented, if not the computer waits two seconds and then flips both tiles back over. selections are then reset. what is acutally happening is that the first tile flips over fine, but the second one will only flip if it's the correct tile. if it's not a match the computer won't flip the tile but still waits it's two seconds (so i know it gets into the correct loop), and then flips over the original tile. all the counters work correctly too so the loops are executing like they should as far as i can tell, here's the logic for the mouseclick using WM_LBUTTONDOWN windows msg, all arrays are [4][4] corresponding to bool(face up, face down), int(image number (1-8)), and bitmaps(g_pTiles[][]) void MouseButtonDown(int x, int y, MOUSE button) { switch(button) { case LEFT: { int iTileX = x / g_pTiles[0]->GetWidth(); int iTileY = y / g_pTiles[0]->GetHeight(); // make sure it hasn't already been turned over if (!g_bTileStates[iTileX][iTileY]) { //see if this is the first tile selected if (g_ptTile1.x == -1) { g_ptTile1.x = iTileX; g_ptTile1.y = iTileY; g_bTileStates[iTileX][iTileY] = true; InvalidateRect(g_pGame->GetWindow(), NULL, FALSE); } else if (g_ptTile2.x == -1) { g_ptTile2.x = iTileX; g_ptTile2.y = iTileY; g_bTileStates[iTileX][iTileY] = true; InvalidateRect(g_pGame->GetWindow(), NULL, FALSE); ++g_iTries; //see if it's a match if (g_iTiles[g_ptTile1.x][g_ptTile1.y] == g_iTiles[g_ptTile2.x][g_ptTile2.y]) { if (++g_iMatches == 8) { TCHAR szText[64]; wsprintf(szText, "You won in %d tries!", g_iTries); MessageBox(g_pGame->GetWindow(), szText, TEXT("Brainiac"), MB_OK); } } else { //turn tiles back over wait(2); g_bTileStates[g_ptTile1.x][g_ptTile1.y] = g_bTileStates[g_ptTile2.x][g_ptTile2.y] = false; InvalidateRect(g_pGame->GetWindow(), NULL, FALSE); } //clear selections g_ptTile1.x = g_ptTile1.y = g_ptTile2.x = g_ptTile2.y = -1; } } return; } and here's the paint function that gets called for the repaint from InvalidateRect(): void GamePaint(HDC hDC) { //Draw tiles int iTileWidth = g_pTiles[0]->;GetWidth(); int iTileHeight = g_pTiles[0]->;GetHeight(); for (int i = 0; i < 4; ++i) for (int j = 0; j < 4; ++j) if (g_bTileStates[i][j] || ( (i == g_ptTile1.x) && (j == g_ptTile1.y)) || ( (i == g_ptTile2.x) && (j == g_ptTile2.y)) ) g_pTiles[g_iTiles[i][j]]->Draw(hDC, i * iTileWidth, j * iTileHeight, TRUE); else g_pTiles[0]->;Draw(hDC, i * iTileWidth, j * iTileHeight, TRUE); } hopefully someone out there can digest all this

Share this post


Link to post
Share on other sites
The problem comes from the wait and/or the InvalidateRect.
InvalidateRect only tells Windows, that the passed rect of the window needs to be repainted, it does NOT repaint immediately.
So if it's the wrong pair, it waits two seconds, and then flips both tiles back again.
When Windows finally redraws your window both tiles are flipped on their back again.

You could try to call RedrawWindow directly after the InvalidateRect that ought to redraw the flipped second tile.

Still, the wait inside there is not optimal. During those two seconds your windows "hangs", as no messages are being processed.

You might try to implement real Windows timers with SetTimer/KillTimer, which calls WM_TIMER.

Share this post


Link to post
Share on other sites
Quote:
Original post by zappernapper
since i'm not familiar w/ the windows timers i'll stick with my wait function. what are the arguments you need to pass to RedrawWindow() ?


No, you shouldn't stick to wait(). To redraw the window, you have to let windows process you message loop. This can't be done if you wait().

You can improve your code by incorporing a message pump in place of the wait:


for (int i=0; i<100; i++)
{
Sleep(20); // Sleep() is better than wait
if (PeekMessage(...))
{
TranslateMessage(...);
DispatchMessage(...);
}
}


This way, you will be able to process messages that may be sent to your app while you were waiting.

Nevertheless, I believe you should try to find a better method - like using timers. Saying 'I don't want to do it because I don't' know is a rather lame excuse. If you don't want to learn new thing, why do you try to learn programming?

Regards,

Share this post


Link to post
Share on other sites
Quote:
Nevertheless, I believe you should try to find a better method - like using timers. Saying 'I don't want to do it because I don't' know is a rather lame excuse. If you don't want to learn new thing, why do you try to learn programming?

Regards,


in all fairness i DID ask how to use the RedrawWindow() function, which btw wasn't answered. it's not that i don't want to learn something new, it's just that i was choosing which new thing i wanted to learn at the moment. i'm horrible at looking up how to do things online (which is the most common response i get when i ask how to use a particular function) and i appreciate YOU showing me what specifically i should do if i were to use sleep. in this particular instance i don't see why the program would need to be processing any other messages because i certainly don't want the user to be clicking ahead of themselves and more than likely all they will be doing is waiting for the game to flip the tiles back over anyways. hopefully you find that a more valid reason than
Quote:
'I don't want to do it because I don't know'
and if u can offer a good reson to be processing msgs anyways i'd appreciate it because then i will be aware of it.

Share this post


Link to post
Share on other sites
oh and i've fixed the prob (still using wait) by incorporating the matching logic into the mousbuttonup msg which works very nicely! the added benefit of using my wait function is that it uses the system clock rather than having the computer (in essence) count to some high number and than tweaking it to an amount of time i like, especially since this can be affected by how fast the processor on the given computer is. i realize that if i were having several things going on at once, having the system stop everything it's doing may not be the best solution, but in this case i think it works sufficiently. and just for the sake of everything, since redraw is apparently not the way to go, how DO i use the windows timers then?

[Edited by - zappernapper on June 23, 2005 7:56:28 AM]

Share this post


Link to post
Share on other sites
To create a timer you'd call SetTimer( hwnd, 1, 2000, NULL );

This will create a timer with the ID of 1. Windows will from now on send a WM_TIMER message to your window about every 2000 ms. This value is not completely exact, and can't usually be smaller than 55 ms. But for the proposed issue this would be exact enough.

So, once you turned the second tile, you'd create the timer. On receiving WM_TIMER (wParam is the ID) you could check for a pair and act accordingly. Then, still inside WM_TIMER, call KillTimer( hwnd, 1 );

This will keep your window responsive since the messages are still being pumped through the loop.


For RedrawWindow, a simple look in the MSDN yields the following:

RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW );

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this