Thread: Moving a bitmap around the screen -- SMOOTHLY

  1. #1
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753

    Moving a bitmap around the screen -- SMOOTHLY

    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.

  2. #2
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    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

  3. #3
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Also without looking at code:

    Use DirectInput.

  4. #4
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753
    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)

  5. #5
    Registered User
    Join Date
    Sep 2002
    Posts
    1,640
    Hm, yes, well it's virutally impossible to make a decent
    game without a game loop
    like this:

    Code:
     while(1)
    {
    printthagfx();
    gettheinput();
    processtheinput();
    }

  6. #6
    Registered User
    Join Date
    Dec 2002
    Posts
    15

    Lightbulb

    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).

    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
    }
    And so on...

  7. #7
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753
    well now it doesn't move at all. here is my main.cpp:
    (btw, MainLoop is under WM_TIMER is that good or no?)
    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;
    }
    I know the DrawShip works good, here is UpdateShip:
    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.

  8. #8
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    You have your message loop...like this..
    Code:
    //Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
      TranslateMessage(&Msg);
      DispatchMessage(&Msg);
    }
    Usually a Game Loop looks like this... it definitely yields better performance..

    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..
      }
    }

  9. #9
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753
    thanks again, i'll be back for more problems in a little bit

  10. #10
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753
    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;
    	}

  11. #11
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    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;
    	}
    Easy there killer! Get that return Msg.wParam out of the loop!

  12. #12
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753
    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;

  13. #13
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    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.

  14. #14
    Unregistered Leeman_s's Avatar
    Join Date
    Oct 2001
    Posts
    753
    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;
    
    }

  15. #15
    Registered User
    Join Date
    Jan 2003
    Posts
    35
    I've noticed that in some of your code examples you have this line:

    Code:
    if( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) )
    My own message pump looks like this:

    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);
    }
    When I change it to PM_REMOVE the action becomes absolutely terrible.

    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:

    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;
    and it works fine. This is from the WndProc switch.

    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Feedback: Functional Specification Wording
    By Ragsdale85 in forum C++ Programming
    Replies: 0
    Last Post: 01-18-2006, 04:56 PM
  2. char copy
    By variable in forum C Programming
    Replies: 8
    Last Post: 02-06-2005, 10:18 PM
  3. i am not able to figure ot the starting point of this
    By youngashish in forum C++ Programming
    Replies: 7
    Last Post: 10-07-2004, 02:41 AM
  4. OpenGL -- Bitmaps
    By HQSneaker in forum Game Programming
    Replies: 14
    Last Post: 09-06-2004, 04:04 PM
  5. bitmap not going onto screen
    By stallion in forum Windows Programming
    Replies: 4
    Last Post: 02-22-2003, 10:07 AM