Solved

Drawing a bitmap with custom function

Posted on 2009-03-29
11
1,338 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
  • 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
 
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
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 

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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
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…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

746 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now