Alright, I'll paste my program along with the executable. It moves around like it should, only when you switch directions it isn't immediate. Try it out to see what I mean. Thanks.
Alright, I'll paste my program along with the executable. It moves around like it should, only when you switch directions it isn't immediate. Try it out to see what I mean. Thanks.
Without looking at the sourcecode (no time):
Don't use WM_KEYDOWN to read input, use GetAsyncKeyState() inside the game loop.
Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling
Also without looking at code:
Use DirectInput.
What do you mean the "game loop"? (This is probably a concept of windows programming I've missed out on due to learning on my own)
Hm, yes, well it's virutally impossible to make a decent
game without a game loop
like this:
Code:while(1) { printthagfx(); gettheinput(); processtheinput(); }
Ok lets try to help out here, what they were talking about above is if you use the GetAsyncKeyState() Win32 function instead of the WM_KEYDOWN it will be faster cause then it doesn't have to jump out of the loop (which would slow it down).
And so on...Code:#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code & 0x8000) ? 1 : 0) #define KEYUP(vk_code) ((GetAsyncKeyState(vk_code & 0x8000) ? 0 : 1) if (KEYDOWN(VK_DOWN)) { //do movement down here } if (KEYDOWN(VK_SPACE)) { //the space bar was pressed, do something }
well now it doesn't move at all. here is my main.cpp:
(btw, MainLoop is under WM_TIMER is that good or no?)
I know the DrawShip works good, here is UpdateShip:Code:#include <windows.h> #include "resource.h" #include "KEYS.h" #include "Ship.h" #include "Player.h" #include "createmask.h" #define KEYDOWN(vk_code) (GetAsyncKeyState(vk_code & 0x8000) ? 1 : 0) #define KEYUP(vk_code) (GetAsyncKeyState(vk_code & 0x8000) ? 0 : 1) const char g_szClassName[] = "myWindowClass"; const int ID_TIMER = 1; const int SHIP_MOVE_DELTA = 2; bool left, right, up, down; void MainLoop() //Main Game Loop { if(KEYDOWN(VK_LEFT)) { left = true; } if(KEYDOWN(VK_RIGHT)) { right = true; } if(KEYDOWN(VK_UP)) { up = true; } if(KEYDOWN(VK_DOWN)) { down = true; } UpdateShip(left, right, up, down); left = right = up = down = false; } //Step 4: The Window Procedure LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: { UINT ret; BITMAP bm; shipvar = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_SHIP)); if(shipvar == NULL) MessageBox(hWnd, "Could not load player.bmp!", "Error!", MB_OK | MB_ICONEXCLAMATION); shipmask = CreateBitmapMask(shipvar, RGB(255, 0, 255)); if(shipmask == NULL) MessageBox(hWnd, "Could not create ship mask!", "Error!", MB_OK | MB_ICONEXCLAMATION); GetObject(shipvar, sizeof(bm), &bm); //player.x = 0; // Starting coordinates //player.y = 0; ZeroMemory(&player, sizeof(player)); player.width = bm.bmWidth; player.height = bm.bmHeight; player.dx = SHIP_MOVE_DELTA; player.dy = SHIP_MOVE_DELTA; ret = SetTimer(hWnd, ID_TIMER, 50, NULL); if(ret == 0) MessageBox(hWnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION); } break; case WM_KEYDOWN: { switch((int)wParam) { case VK_ESCAPE: PostQuitMessage(0); break; } } break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_PAINT: { RECT rcClient; PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); //main DC GetClientRect(hWnd, &rcClient); DrawShip(hDC, &rcClient); EndPaint(hWnd, &ps); } break; case WM_TIMER: { RECT rcClient; HDC hDC = GetDC(hWnd); GetClientRect(hWnd, &rcClient); MainLoop(); DrawShip(hDC, &rcClient); //use for alien ships ReleaseDC(hWnd, hDC); } case WM_COMMAND: switch(LOWORD(wParam)) { case ID_FILE_EXIT: PostQuitMessage(0); break; case ID_STUFF_GO: MessageBox(hWnd, "You clicked go!", "GO!", MB_OK); break; } break; case WM_DESTROY: KillTimer(hWnd, ID_TIMER); DeleteObject(shipmask); DeleteObject(shipvar); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hWnd; MSG Msg; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)CreateSolidBrush(COLOR_WINDOW+1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);; wc.lpszClassName = g_szClassName; wc.hIconSm = (HICON)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON)); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Windows Regristration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } //Step 2: Creating the Window hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "Lee's Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); if(hWnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); //Step 3: The Message Loop while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }
Code:void UpdateShip(bool left, bool right, bool up, bool down) // I don't want it to move anywhere yet { if(left == true) player.x -= player.dx; if(up == true) player.y -= player.dy; if(right == true) player.x += player.dx; if(down == true) player.y += player.dy; }
Last edited by Leeman_s; 12-23-2002 at 06:13 PM.
You have your message loop...like this..
Usually a Game Loop looks like this... it definitely yields better performance..Code://Step 3: The Message Loop while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); }
Code:BOOL bDone = false; while( !bDone ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { if( msg.message == WM_QUIT ) bDone = TRUE; else { TranslateMessage( &msg ); DispatchMessage( &msg ); } } else if( !bDone ) { // Main game code goes here // Check collision... // Check for input... // Draw frame.. } }
thanks again, i'll be back for more problems in a little bit
damnit now it exits right away:
Code:while(bDone == false) { if( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) ) { if( Msg.message == WM_QUIT ) bDone = true; else { TranslateMessage(&Msg); DispatchMessage(&Msg); } } else if(bDone == false) { RECT rcClient; HDC hDC = GetDC(hWnd); GetClientRect(hWnd, &rcClient); MainLoop(); DrawShip(hDC, &rcClient); //use for alien ships ReleaseDC(hWnd, hDC); } return Msg.wParam; }
Easy there killer! Get that return Msg.wParam out of the loop!Originally posted by Leeman_s
damnit now it exits right away:
Code:while(bDone == false) { if( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) ) { if( Msg.message == WM_QUIT ) bDone = true; else { TranslateMessage(&Msg); DispatchMessage(&Msg); } } else if(bDone == false) { RECT rcClient; HDC hDC = GetDC(hWnd); GetClientRect(hWnd, &rcClient); MainLoop(); DrawShip(hDC, &rcClient); //use for alien ships ReleaseDC(hWnd, hDC); } return Msg.wParam; }
how about this one? (it works, does it look good?):
Code:while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); //Game stuff RECT rcClient; HDC hDC = GetDC(hWnd); GetClientRect(hWnd, &rcClient); MainLoop(); DrawShip(hDC, &rcClient); //use for alien ships ReleaseDC(hWnd, hDC); } return Msg.wParam;
You should use the other one. Basically you are using PeekMessage to see if you have anything waiting for you, if not you can just do your main game update. This way you only dispatch messages that are currently in your message queue. You can read up probably anywhere on the other benefits of this kind of loop. The way you just posted is not favorable. I'll be on later tonight to discuss this more if you'd like. Did the way I posted not work after you took the return out? It should have.
well anyhow, another thing is that the VK things don't work. I used the code provided by the other guy.
Code:#include <windows.h> #include "resource.h" #include "KEYS.h" #include "Ship.h" #include "Player.h" #include "createmask.h" #define KEYDOWN(vk_code) (GetAsyncKeyState(vk_code & 0x8000) ? 1 : 0) #define KEYUP(vk_code) (GetAsyncKeyState(vk_code & 0x8000) ? 0 : 1) const char g_szClassName[] = "myWindowClass"; const int ID_TIMER = 1; const int SHIP_MOVE_DELTA = 2; bool left, right, up, down; bool bDone = false; int iMessage=0; //old message void MainLoop() //Main Game Loop { if(KEYDOWN(VK_LEFT)) { left = true; } if(KEYDOWN(VK_RIGHT)) { right = true; } if(KEYDOWN(VK_UP)) { up = true; } if(KEYDOWN(VK_DOWN)) { down = true; } UpdateShip(left, right, up, down); left = right = up = down = false; } //Step 4: The Window Procedure LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: { UINT ret; BITMAP bm; shipvar = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_SHIP)); if(shipvar == NULL) MessageBox(hWnd, "Could not load player.bmp!", "Error!", MB_OK | MB_ICONEXCLAMATION); shipmask = CreateBitmapMask(shipvar, RGB(255, 0, 255)); if(shipmask == NULL) MessageBox(hWnd, "Could not create ship mask!", "Error!", MB_OK | MB_ICONEXCLAMATION); GetObject(shipvar, sizeof(bm), &bm); //player.x = 0; // Starting coordinates //player.y = 0; ZeroMemory(&player, sizeof(player)); player.width = bm.bmWidth; player.height = bm.bmHeight; player.dx = SHIP_MOVE_DELTA; player.dy = SHIP_MOVE_DELTA; ret = SetTimer(hWnd, ID_TIMER, 50, NULL); if(ret == 0) MessageBox(hWnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION); } break; case WM_KEYDOWN: { switch((int)wParam) { case VK_ESCAPE: PostQuitMessage(0); break; } } break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_PAINT: { RECT rcClient; PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); //main DC GetClientRect(hWnd, &rcClient); DrawShip(hDC, &rcClient); EndPaint(hWnd, &ps); } break; case WM_TIMER: { RECT rcClient; HDC hDC = GetDC(hWnd); GetClientRect(hWnd, &rcClient); //MainLoop(); //DrawShip(hDC, &rcClient); //use for alien ships ReleaseDC(hWnd, hDC); } case WM_COMMAND: switch(LOWORD(wParam)) { case ID_FILE_EXIT: PostQuitMessage(0); break; case ID_STUFF_GO: MessageBox(hWnd, "You clicked go!", "GO!", MB_OK); break; } break; case WM_DESTROY: KillTimer(hWnd, ID_TIMER); DeleteObject(shipmask); DeleteObject(shipvar); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hWnd; MSG Msg; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)CreateSolidBrush(COLOR_WINDOW+1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);; wc.lpszClassName = g_szClassName; wc.hIconSm = (HICON)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON)); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Windows Regristration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } //Step 2: Creating the Window hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "Lee's Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); if(hWnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); //Step 3: The Message Loop while(iMessage = (GetMessage(&Msg, hWnd, 0, 0) > 0)) { if(iMessage > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } RECT rcClient; HDC hDC = GetDC(hWnd); GetClientRect(hWnd, &rcClient); //Game stuff MainLoop(); DrawShip(hDC, &rcClient); //use for alien ships ReleaseDC(hWnd, hDC); } return Msg.wParam; }
I've noticed that in some of your code examples you have this line:
My own message pump looks like this:Code:if( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) )
When I change it to PM_REMOVE the action becomes absolutely terrible.Code:if (PeekMessage(&Msg, 0, 0, 0, PM_NOREMOVE)) { int result = GetMessage(&Msg, 0, 0, 0); if (!result) { quit=true; break; } TranslateMessage(&Msg); DispatchMessage(&Msg); }
I tried the GetAsyncKeyState() thing but for some reason that yielded worse performance than my current setup, which uses WM_KEYDOWN.
I use a simple switch like this:
and it works fine. This is from the WndProc switch.Code:case WM_KEYDOWN: switch(wParam) { case VK_UP: nextGMState=UP; break; case VK_DOWN: nextGMState=DOWN; break; case VK_LEFT: nextGMState=LEFT; break; case VK_RIGHT: nextGMState=RIGHT; break; default: nextGMState=IDLE; break; } break;
Basically, moving the controls outside the WndProc function to the game loop actually slowed things down. And now that I think about it, I know what I did wrong ... I'll try it again and see what happens.
But the above method should work. If you change your message pump to include the PM_NOREMOVE flag you should get much better performance, assuming you also move your controls back to WndProc.