Solved

Drawing a bitmap with custom function

Posted on 2009-03-29
11
1,342 Views
Last Modified: 2013-12-14
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
0
Comment
Question by:psycho_blood
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 2
  • +1
11 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 250 total points
ID: 24014377
This is not a matter of 'float' or 'int', but how you position the bitmap - your code

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);
    }
}

will assign a random position on each call, which is not what you want to do. Better try something like
int nX = 0, nY = 0; // globals
 
void Game_Run()
{
    //this is called once every frame
    //do not include your own loop here!
    
    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);
    }
}

Open in new window

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 250 total points
ID: 24014391
Oh, BTW - for performance reasons, move

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

into 'Game_Init()' instead of caling that over and over again each time.
0
 

Author Comment

by:psycho_blood
ID: 24014975
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

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 86

Assisted Solution

by:jkr
jkr earned 250 total points
ID: 24020502
A path definitely would be possible - but you'd have to provide the poins that make up that path or at least a formula that describes it.
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 250 total points
ID: 24024214
I think you want to make the asteroid move in a straight line and bounce off of the edges...
If so, then you need to keep track of X,Y outside of Game_Run.  Something like the attached.  Not that I did not actually complie that, so sorry for any syntax errors...

int nCurX=20;  // globals, for now
int nCurY=0;  
int nCurStepX = 2; // Move left-to-right in two-dot steps
int nCurStepY = 1; // Move top to bottom
 
//this is called once every frame do not include your own loop here!
void Game_Run()
{      
    RECT rect;
    GetClientRect(global_hwnd, &rect);
 
    nCurX  = nCurStepX;  // move one step horizonral
    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", nX, nY);
}
 

Open in new window

0
 

Author Comment

by:psycho_blood
ID: 24035744
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

0
 
LVL 49

Assisted Solution

by:DanRollins
DanRollins earned 250 total points
ID: 24036097
Dang it, I knew that if i did not test, I'd make a bonehesad mistake.  Sorry.
   nCurX  += nCurStepX;  // move one step horizonral
   nCurY  += nCurStepY;  // move one step vertical
change the = to += (as shown).
 
0
 

Author Comment

by:psycho_blood
ID: 24036217
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!
0
 

Author Closing Comment

by:psycho_blood
ID: 31564054
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!
0
 

Expert Comment

by:CollegeKid101
ID: 25085749
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.
0
 

Expert Comment

by:CollegeKid101
ID: 25085763
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!
0

Featured Post

Secure Your Active Directory - April 20, 2017

Active Directory plays a critical role in your company’s IT infrastructure and keeping it secure in today’s hacker-infested world is a must.
Microsoft published 300+ pages of guidance, but who has the time, money, and resources to implement? Register now to find an easier way.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question