[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now

x
?
Solved

Drawing a bitmap with custom function

Posted on 2009-03-29
11
Medium Priority
?
1,352 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 1000 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 1000 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
Industry Leaders: 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 1000 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 1000 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 1000 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

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
Suggested Courses

656 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