Link to home
Start Free TrialLog in
Avatar of psycho_blood
psycho_blood

asked on

Drawing a bitmap with custom function

In the code posted below, a window is created and an "asteroid" is randomly drawn inside the window on each frame. Is there a way to modify the DrawBitmap function in order to obtain a single asteroid slowly floating around the window? I modified my x and y variables from int to float type but it didn't work. Also, I read that I could mask the previous location of the asteroid and fill it with the same color as the background, but I don't know exactly how to do this.
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
#define APPTITLE "Game Loop"
 
//function prototypes
LRESULT CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);
ATOM MyRegisterClass(HINSTANCE);
BOOL InitInstance(HINSTANCE,int);
void DrawBitmap(HDC,char*,float,float);
void Game_Init();
void Game_Run();
void Game_End();
 
 
//local variables
HWND global_hwnd;
HDC global_hdc;
 
 
//the window event callback function
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    global_hwnd = hWnd;
    global_hdc = GetDC(hWnd);
 
	switch (message) 
	{
		case WM_DESTROY:
            Game_End();
			PostQuitMessage(0);
			break;
    }
	return DefWindowProc(hWnd, message, wParam, lParam);
}
 
//helper function to set up the window properties
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    //create the window class structure
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 
 
    //fill the struct with info
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra	 = 0;
    wc.cbWndExtra	 = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APPTITLE;
    wc.hIconSm       = NULL;
 
    //set up the window with the class info
    return RegisterClassEx(&wc);
 
}
 
//helper function to create the window and refresh it
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;
 
    //create a new window
    hWnd = CreateWindow(
       APPTITLE,              //window class
       APPTITLE,              //title bar
       WS_OVERLAPPEDWINDOW,   //window style
       CW_USEDEFAULT,         //x position of window
       CW_USEDEFAULT,         //y position of window
       500,                   //width of the window
       400,                   //height of the window
	   NULL,                  //parent window
       NULL,                  //menu
       hInstance,             //application instance
       NULL);                 //window parameters
 
    //was there an error creating the window?
    if (!hWnd)
      return FALSE;
 
    //display the window
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    return TRUE;
}
 
 
//entry point for a Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR     lpCmdLine,
                   int       nCmdShow)
{
    int done = 0;
	MSG msg;
 
	// register the class
	MyRegisterClass(hInstance);
 
 
    // initialize application
	if (!InitInstance (hInstance, nCmdShow)) 
		return FALSE;
 
    //initialize the game
    Game_Init();
 
    // main message loop
	while (!done)
	{
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        {
            //look for quit message
            if (msg.message == WM_QUIT)
                done = 1;
 
            //decode and pass messages on to WndProc
            TranslateMessage(&msg);
		    DispatchMessage(&msg);
        }
        
        //process game loop
        Game_Run();
	}
 
	return msg.wParam;
}
 
void DrawBitmap(HDC hdcDest, char *filename, float x, float y)
{
    HBITMAP image;
    BITMAP bm;
	HDC hdcMem;
 
   image = (HBITMAP)LoadImage(0,"asteroid.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
   
   //read the bitmap's properties
    GetObject(image, sizeof(BITMAP), &bm);
 
    //create a device context for the bitmap
    hdcMem = CreateCompatibleDC(global_hdc);
	SelectObject(hdcMem, image);
 
    //draw the bitmap to the window (bit block transfer)
    BitBlt( 
        global_hdc,              //destination device context
        x, y,                    //x,y location on destination
        bm.bmWidth, bm.bmHeight, //width,height of source bitmap
	    hdcMem,                  //source bitmap device context
        0, 0,                    //start x,y on source bitmap
        SRCCOPY);                //blit method
 
    //delete the device context and bitmap
    DeleteDC(hdcMem);
    DeleteObject((HBITMAP)image);
}
 
 
void Game_Init()
{
    //initialize the game...
    //load bitmaps, meshes, textures, sounds, etc.
    
 
    srand(time_t(NULL));
}
 
void Game_Run()
{
    //this is called once every frame
    //do not include your own loop here!
    
    float x = 0, y = 0;
    RECT rect;
    GetClientRect(global_hwnd, &rect);
 
    if (rect.right > 0)
    {
        x = rand() % (rect.right - rect.left);
        y = rand() % (rect.bottom - rect.top);
        DrawBitmap(global_hdc, "asteroid.bmp", x, y);
    }
}
 
void Game_End()
{
 
}

Open in new window

asteroid.bmp
SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of psycho_blood
psycho_blood

ASKER

I saw both of your comments, but first I tried substituting my Game_run() function for what you proposed and see how it worked. The program compiles and runs, but the asteroid seems to stay vibrating at the upper left corner of the window, which is better than I had before. Now my question would be if there is a way to make the asteroid travel through a path, similar to the white block that appears on the DirectX's DirectDraw test. Is this possible by using the rand() function?
// Beginning Game Programming
// Chapter 4
// GameLoop project
 
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
#define APPTITLE "Game Loop"
 
//function prototypes
LRESULT CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);
ATOM MyRegisterClass(HINSTANCE);
BOOL InitInstance(HINSTANCE,int);
void DrawBitmap(HDC,char*,int,int);
void Game_Init();
void Game_Run();
void Game_End();
 
 
//local variables
HWND global_hwnd;
HDC global_hdc;
 
 
//the window event callback function
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    global_hwnd = hWnd;
    global_hdc = GetDC(hWnd);
 
	switch (message) 
	{
		case WM_DESTROY:
            Game_End();
			PostQuitMessage(0);
			break;
    }
	return DefWindowProc(hWnd, message, wParam, lParam);
}
 
//helper function to set up the window properties
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    //create the window class structure
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 
 
    //fill the struct with info
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra	 = 0;
    wc.cbWndExtra	 = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APPTITLE;
    wc.hIconSm       = NULL;
 
    //set up the window with the class info
    return RegisterClassEx(&wc);
 
}
 
//helper function to create the window and refresh it
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;
 
    //create a new window
    hWnd = CreateWindow(
       APPTITLE,              //window class
       APPTITLE,              //title bar
       WS_OVERLAPPEDWINDOW,   //window style
       CW_USEDEFAULT,         //x position of window
       CW_USEDEFAULT,         //y position of window
       500,                   //width of the window
       400,                   //height of the window
	   NULL,                  //parent window
       NULL,                  //menu
       hInstance,             //application instance
       NULL);                 //window parameters
 
    //was there an error creating the window?
    if (!hWnd)
      return FALSE;
 
    //display the window
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    return TRUE;
}
 
 
//entry point for a Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR     lpCmdLine,
                   int       nCmdShow)
{
    int done = 0;
	MSG msg;
 
	// register the class
	MyRegisterClass(hInstance);
 
 
    // initialize application
	if (!InitInstance (hInstance, nCmdShow)) 
		return FALSE;
 
    //initialize the game
    Game_Init();
 
    // main message loop
	while (!done)
	{
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        {
            //look for quit message
            if (msg.message == WM_QUIT)
                done = 1;
 
            //decode and pass messages on to WndProc
            TranslateMessage(&msg);
		    DispatchMessage(&msg);
        }
        
        //process game loop
        Game_Run();
	}
 
	return msg.wParam;
}
 
void DrawBitmap(HDC hdcDest, char *filename, int x, int y)
{
	 HBITMAP image;
    BITMAP bm;
	HDC hdcMem;
 
   image = (HBITMAP)LoadImage(0,"asteroid.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
   
   //read the bitmap's properties
    GetObject(image, sizeof(BITMAP), &bm);
 
    //create a device context for the bitmap
    hdcMem = CreateCompatibleDC(global_hdc);
	SelectObject(hdcMem, image);
   
	//draw the bitmap to the window (bit block transfer)
    BitBlt( 
        global_hdc,              //destination device context
        x, y,                    //x,y location on destination
        bm.bmWidth, bm.bmHeight, //width,height of source bitmap
	    hdcMem,                  //source bitmap device context
        0, 0,                    //start x,y on source bitmap
        SRCCOPY);                //blit method
 
    //delete the device context and bitmap
    DeleteDC(hdcMem);
    DeleteObject((HBITMAP)image);
}
 
 
void Game_Init()
{
    //initialize the game...
    //load bitmaps, meshes, textures, sounds, etc.
   
    srand(time_t(NULL));
}
 
void Game_Run()
{
    //this is called once every frame
    //do not include your own loop here!
    
	int nX = 0;
	int nY = 0;
    RECT rect;
    GetClientRect(global_hwnd, &rect);
 
    if (rect.right > 0)
    {
        int x = rand();
        int y = rand();
 
        if (x > RAND_MAX / 2) {nX++;} else {nX--;}
 
        if (y > RAND_MAX / 2) {nY++;} else {nY--;}
 
        if (nX > rect.right) nX = 0;
        if (nX < 0) nX = rect.right;
 
        if (nY > rect.bottom) nY = 0;
        if (nX < 0) nX = rect.bottom;
 
        DrawBitmap(global_hdc, "asteroid.bmp", nX, nY);
    }
}
 
 
 
void Game_End()
{
 
}

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I used your function but I had to change nX and nY to nCurX and nCurY. I think this is what you meant to write when calling DrawBitmap. Now the program compiles but the asteroid does not move at all. I will read your function later to see if I can understand why is that.
void Game_Run()
{      
    RECT rect;
    GetClientRect(global_hwnd, &rect);
 
	nCurX  = nCurStepX;  // move one step horizontal
    nCurY  = nCurStepY;  // move one step vertical
 
    if ( nCurX > rect.right ) {  // at right edge?  Switch to moving to the left
       nCurStepX *= -1; // change  1 to -1 or -1 to  1
       nCurX= rect.right;
    }
    if ( nCurX < rect.left ) {  // at left edge?  Switch to moving to the right
       nCurStepX *= -1; // change  1 to -1 or -1 to  1
       nCurX= rect.left;
    }
    if ( nCurY > rect.bottom ) { // at bottom?  Switch to moving up
       nCurStepY *= -1; // change  1 to -1 or -1 to  1
       nCurY= rect.bottom;
    }
    if ( nCurY < rect.top ) { // at top?  Switch to moving down
       nCurStepY *= -1; // change  1 to -1 or -1 to  1
       nCurY= rect.top;
    }
    DrawBitmap(global_hdc, "asteroid.bmp", nCurX, nCurY);
}

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Before your comment, I tried this:

nCurX = nCurStepX++;
nCurY = nCurStepY++;

Unfortunately, it didn't work. Then, I came back and noticed your comment, and that solved the problem.

Thanks!
I splitted the points because all of you tried to help me. I hope my decision does not make anyone angry!
Once again, thank you all!
I tried to compile your code but instead of using the regular global variables I used static int values. For some odd reason when I code in the if statements for the top and the left hand sides, my asteroid picture shoots off in the upper left hand corner and disappears.   My code matches yours with the exception of the static int values. Just curious if you know of some reason for this.
I want to retract my statement above (can't find an edit button) I mis read the > and < signs in the if statements. Noobish mistake on my part. You guys are amazing, you saved my whole week!