-
GDI sprite (Win32 API)
Please help... how can I make sprite (simple picture moving when pressed arrows)
I thought something like this:
when arrow pressed, then
1) delete previous picture from screen
2) calculate new coordinates
3) show picture using BitBlt()
I have done step 2 and step 3 (it works), put how can I do step 1 -> "delete" previous picture from screen? Or is there any better way making sprite?
I have tried to delete previous picture using rectangle ->
FillRect(..., ..., GetStockObject(WHITE_BRUSH)); but thats no solution what if the background is a image?... and using this the picture starts to blink.
Here's my code and I' am using DevC++ compilator:
Code:
#include <string>
#include <iostream>
#include <sstream>
#include <math.h>
#include <windows.h>
#define KEYSTATE(vknum) ((GetAsyncKeyState(vknum) & 0x8000) ? TRUE : FALSE)
using namespace std;
HINSTANCE hInst;
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
double x = 50;
double y = 50;
double speed = 0.05;
int max_x = 400;
int max_y = 200;
int min_x = 0;
int min_y = 0;
HWND hWnd;
HDC hDC, MemDCExercising;
HANDLE bmpExercising;
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndCls;
static char szAppName[] = "BitmapIntro";
MSG Msg;
hInst = hInstance;
WndCls.cbSize = sizeof(WndCls);
WndCls.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
WndCls.lpfnWndProc = WindProcedure;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hInstance = hInst;
WndCls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = szAppName;
WndCls.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szAppName,
"Sprite",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
hDC = GetDC(hWnd);
bmpExercising = LoadImage(hInst, "C:\\mypic.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
// Create a memory device compatible with the above DC variable
MemDCExercising = CreateCompatibleDC(hDC);
// Select the new bitmap
SelectObject(MemDCExercising, bmpExercising);
while( GetMessage(&Msg, NULL, 0, 0) )
{
TranslateMessage(&Msg);
DispatchMessage( &Msg);
}
return static_cast<int>(Msg.wParam);
}
void point (HWND hWnd)
{
int xC = (int) round(x);
int yC = (int) round(y);
if(xC>max_x){ xC=max_x; x=max_x; }
if(yC>max_y){ yC=max_y; y=max_y; }
if(xC<min_x){ xC=min_x; x=min_x; }
if(yC<min_y){ yC=min_y; y=min_y; }
//////////////////////////////////////////////////////////////////////////
/* THIS IS THE PLACE WHERE DELETE PREVOIUS IMAGE */
////////////////////////////////////////////////////////////////////////
BitBlt(hDC, xC, yC, 400, 400, MemDCExercising, 0, 0, SRCCOPY);
CancelDC(hDC);
ReleaseDC(hWnd, hDC);
}
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
if(KEYSTATE(VK_UP)){ y-=speed; point(hWnd); }
if(KEYSTATE(VK_DOWN)){ y+=speed; point(hWnd); }
if(KEYSTATE(VK_LEFT)){ x-=speed; point(hWnd); }
if(KEYSTATE(VK_RIGHT)){ x+=speed; point(hWnd); }
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
case WM_PAINT:
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
Thank you!
-
wrong message board, try windows programming or game programming
-
As mentioned by ay_okay, this should be under the Windows or Game message boards.
First, I'd just like to point out:
Code:
CancelDC(hDC);
ReleaseDC(hWnd, hDC);
You don't want these two lines here. Every time you call point(), in other words whenever you have an arrow pressed down, you:
1) Try to draw something
2) Cancel drawing it, although (I think) that only works if called from a different thread
3) Release your HDC, so you can't use it anymore
Number 1 is OK. #2 is pointless if not harmful, and #3 is sinister.
Next, you have your if(KEYSTATE) stuff in the wrong place - it's in the Window procedure, which is NOT called in each frame. I'd be surprise if you didn't get jerky and unpredictable movement. You'll need to modify your while(GetMessage()) loop to use PeekMessage() with the PM_REMOVE flag, and then get it to pump your if(KEYSTATE) code only after all pending messages have already been handled by TranslateMessage() and DispatchMessage(). Note that your if(KEYSTATE) code goes together with the message loop, NOT inside the window procedure. Also, after your message loop, you need to clean up your HDC and HBITMAP (not inside the Window procedure).
After you've got that fixed up, you can solve the flickering problem by reading about double-buffering. It involves having a separate HDC that you draw everything to (first draw the background, then draw your sprites on top of the background) each frame, and after you're done drawing on it, you BitBlt the entire HDC to your main window.
Good luck!
-
thank you for a reply... I fix those things.
I am very grateful, if someone can give me a working code (or link) for something similary... I have searched so many days from Google and MSDN. Best way to learn is to examine working code.
I posted this thread in "Game Programming" ->
http://cboard.cprogramming.com/showthread.php?t=66807