bitmap animation with Timer???
Im trying to use bitmaps in rapid succession with a timer, but it is all a blur. PLEASE HELP.
Your post is less then discriptive but i'll take a shot at it. If your animation is literally a blur its probably due to the fact that the bitmap is animating at the full speed of the computer. you could slow it down by adding sleep statements or by having an internal counter that would trigger the animation
I recommend the first one because it alows you to have control over each bitmaps animation speed (you could pass the value of counter as a constructor param). If this is not what you mean by "its all a blur", such as "I learned it somewhere but have a hard time remembering the details" feel free to correct my assumption
Hope I Helped [smile]
int main(){ X.Animate();}void Class::Animate(){ if(Counter < 1000) { ++Counter; return; else //next frame of animation}
or using sleep it would just beint main(){ Sleep(10); X.Animate();}void Class:Animate(){ //next frame}
I recommend the first one because it alows you to have control over each bitmaps animation speed (you could pass the value of counter as a constructor param). If this is not what you mean by "its all a blur", such as "I learned it somewhere but have a hard time remembering the details" feel free to correct my assumption
Hope I Helped [smile]
That sorta worked. It slowed down a bit. But I decided that I would use somebody else's class, which used QueryPerformanceCounter(). I start the counter, if the time that hasn't passed isn't enough, then I update the time.
All of this is embedded into my Draw() function. Here is my code.
void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey, bool timer, int time) //Draw with delay
{
HINSTANCE hDraw = hThisInstance;
HDC hDCdraw = GetDC(hwnd);
HANDLE draw = LoadImage( hDraw, FileName, IMAGE_BITMAP, sizex, sizey, LR_LOADFROMFILE | LR_CREATEDIBSECTION );
HDC hDCdrawOFF = CreateCompatibleDC( GetDC(hwnd) );
CreateCompatibleBitmap( hDCdrawOFF, sizex, sizey );
hDCdraw = BeginPaint(hwnd, &ps); //Start paint with backbuffer DC
SelectObject(hDCdrawOFF, draw);
GetObject( draw, sizeof(BITMAP), NULL );
if(timer)
{
double Counter = InitTimer(); //Start Timer
Counter = CurrentTime(); //Start counting time
if (Counter < time) //If time not passed by
Counter = CurrentTime(); //Update time
else
BitBlt( GetDC(hwnd), x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY); //If time gone by, draw BMP
}
//Cleanup
ReleaseDC( hwnd, hDCdrawOFF);
ReleaseDC( hwnd, hDCdraw );
DeleteDC( hDCdrawOFF);
DeleteDC( hDCdraw);
DeleteObject( draw );
EndPaint(hwnd, &ps); //End paint
}
And here is the timer function
double InitTimer() //Start Timer
{
__int64 time;
QueryPerformanceFrequency((LARGE_INTEGER*)&TimeFrequency);
QueryPerformanceCounter((LARGE_INTEGER*)&time);
TimeBegin = (double)time / TimeFrequency;
return TimeBegin;
}
double CurrentTime() //Get time
{
__int64 time;
QueryPerformanceCounter((LARGE_INTEGER*)&time);
return ((double)time / TimeFrequency) - TimeBegin;
}
I don't know. Please help me.
P.S. I have a four KB memory leak. I can't find it. I will post my full code next.
All of this is embedded into my Draw() function. Here is my code.
void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey, bool timer, int time) //Draw with delay
{
HINSTANCE hDraw = hThisInstance;
HDC hDCdraw = GetDC(hwnd);
HANDLE draw = LoadImage( hDraw, FileName, IMAGE_BITMAP, sizex, sizey, LR_LOADFROMFILE | LR_CREATEDIBSECTION );
HDC hDCdrawOFF = CreateCompatibleDC( GetDC(hwnd) );
CreateCompatibleBitmap( hDCdrawOFF, sizex, sizey );
hDCdraw = BeginPaint(hwnd, &ps); //Start paint with backbuffer DC
SelectObject(hDCdrawOFF, draw);
GetObject( draw, sizeof(BITMAP), NULL );
if(timer)
{
double Counter = InitTimer(); //Start Timer
Counter = CurrentTime(); //Start counting time
if (Counter < time) //If time not passed by
Counter = CurrentTime(); //Update time
else
BitBlt( GetDC(hwnd), x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY); //If time gone by, draw BMP
}
//Cleanup
ReleaseDC( hwnd, hDCdrawOFF);
ReleaseDC( hwnd, hDCdraw );
DeleteDC( hDCdrawOFF);
DeleteDC( hDCdraw);
DeleteObject( draw );
EndPaint(hwnd, &ps); //End paint
}
And here is the timer function
double InitTimer() //Start Timer
{
__int64 time;
QueryPerformanceFrequency((LARGE_INTEGER*)&TimeFrequency);
QueryPerformanceCounter((LARGE_INTEGER*)&time);
TimeBegin = (double)time / TimeFrequency;
return TimeBegin;
}
double CurrentTime() //Get time
{
__int64 time;
QueryPerformanceCounter((LARGE_INTEGER*)&time);
return ((double)time / TimeFrequency) - TimeBegin;
}
I don't know. Please help me.
P.S. I have a four KB memory leak. I can't find it. I will post my full code next.
As I said I would, here is my entire code, so maybe someone can find my 4KB memory leak. Please help. Thx.
Main.cpp
And here is my heade file
Main.h
I would appreciate any comments. About the code, new code, or anything else. Thanks everyone.
Please help me. GDI is hard, but a good learing experience.
Main.cpp
#include "main.h"/* Declare Windows procedure */LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);/* Make the class name into a global variable */char szClassName[ ] = "GOH";sPlayer Player;sEnemy Demon;int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) /* This is the handle for our window */{ MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = 0; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (hThisInstance, MAKEINTRESOURCE(GOH_ICON)); wincl.hIconSm = LoadIcon (hThisInstance, MAKEINTRESOURCE(GOH_ICON)); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = CreateSolidBrush(BG);; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "Gates of Heaven", /* Title Text */ WS_MINIMIZEBOX | WS_SYSMENU, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 900, /* The programs width */ 600, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ NULL, /* No menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow (hwnd, nFunsterStil); /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } /* The program return-value is 0 - The value that PostQuitMessage() gave */ return messages.wParam;}/* This function is called by the Windows function DispatchMessage() */LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) /* handle the messages */ { case WM_DESTROY: if(MessageBox( hwnd, "Do you want to save your current progress before you exit?", "Save Current Progress?", MB_YESNO | MB_ICONQUESTION) == IDYES) save(); //DeleteDC(hdc); PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; case WM_CREATE: SetRect( &pHealth, 0, 0, 100, 20 ); SetRect( &pMana, 0, 30, 100, 50 ); SetRect( &pAttack, 0, 60, 100, 80); SetRect( &pLevel, 0, 90, 100, 120); SetRect( &pXP, 0, 120, 100, 160); Player.facing = 2; //Facing east hdc = BeginPaint(hwnd, &ps); SetRect( &stats, 0, 550, 100, 600 ); FillRect(hdc, &stats, CreateSolidBrush(Black)); EndPaint(hwnd, &ps); if(MessageBox( hwnd, "Do you want to load a saved game?", "Load Saved Game?", MB_YESNO | MB_ICONQUESTION) == IDYES) { load(); InvalidateRect(hwnd,NULL,TRUE); } else { Init(); InvalidateRect(hwnd,NULL,TRUE); } eInit(1); Player.dead = false; break; case WM_KEYUP: switch(wParam) { case VK_F1: if(MessageBox( hwnd, "Are you sure that you want to save your current progress?", "Save Game?", MB_YESNO | MB_ICONQUESTION) == IDYES) { save(); } else return (1); break; case 0x41: //A while (!Demon.dead) { AttackE(); Sleep(aDelay); attack = true; Attack(false); Attack(true); } if(Demon.dead) { if(attack) { Player.xp = Player.xp + Demon.xp; InvalidateRect(hwnd,NULL,TRUE); } attack = false; } if(Player.xp >= 1000) { LevelUp(2); InvalidateRect(hwnd,NULL,TRUE); } if(Player.xp >= 2000) { LevelUp(3); InvalidateRect(hwnd,NULL,TRUE); } if(Player.xp >= 3000) { LevelUp(4); InvalidateRect(hwnd,NULL,TRUE); } if(Player.xp >= 4000) { LevelUp(5); InvalidateRect(hwnd,NULL,TRUE); } if(Player.xp >= 5000) { LevelUp(6); InvalidateRect(hwnd,NULL,TRUE); } break; case 0x4E: //N if(MessageBox( hwnd, "Are you sure that you want to start a new game and lose your current progress?", "New Game?", MB_YESNO | MB_ICONQUESTION) == IDYES) { Init(); InvalidateRect(hwnd,NULL,TRUE); } else return (1); break; case 0x4C: //L if(MessageBox( hwnd, "Are you sure that you want to load and lose your current progress?", "Load?", MB_YESNO | MB_ICONQUESTION) == IDYES) { load(); InvalidateRect(hwnd,NULL,TRUE); } else return (1); break; case VK_ESCAPE: if(MessageBox( hwnd, "Do you want to save your current progress before you exit?", "Save Current Progress?", MB_YESNO | MB_ICONQUESTION) == IDYES) save(); ReleaseDC(hwnd, hdc); DeleteDC(hdc); PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; } break; case WM_KEYDOWN: switch(wParam) { case VK_UP: if(testY != 0) //If not leaving screen { Player.facing = 1; testY = (testY - speed); InvalidateRect(hwnd,NULL,FALSE); } break; case VK_DOWN: if(testY != (550 - 96)) //If not leaving screen { Player.facing = 3; testY = (testY + speed); InvalidateRect(hwnd,NULL,FALSE); } break; case VK_LEFT: if( testX != 100) //If not hitting stats { Player.facing = 4; //Move left testX = (testX - speed); InvalidateRect(hwnd,NULL,FALSE); } break; case VK_RIGHT: if(testX != (900 - testS)) //If not leaving screen { Player.facing = 2; testX = (testX + speed); InvalidateRect(hwnd,NULL,FALSE); } break; } break; case WM_PAINT: wsprintf(Phealth,"Health: %d", Player.health); wsprintf(Pmana,"Mana: %d", Player.mana); wsprintf(Pattack, "Attack: %d", Player.attack); wsprintf(Plevel,"Level: %d", Player.level); wsprintf(Pxp, "XP: %d", Player.xp); hdc = BeginPaint(hwnd, &ps); SetBkMode(hdc, TRANSPARENT); SetTextColor( hdc, TXT ); if(Player.dead) { GetClientRect (hwnd, &screen); FillRect(hdc, &screen, CreateSolidBrush(BG)); DrawText( hdc, "YOU DIED!!!", -1, &screen, DT_SINGLELINE | DT_CENTER | DT_VCENTER ); EndPaint(hwnd, &ps); DeleteObject( &screen ); } else if (!Player.dead) { //Draw stats DrawText(hdc, Phealth, -1, &pHealth, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Pmana, -1, &pMana, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Pattack, -1, &pAttack, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Plevel, -1, &pLevel, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Pxp, -1, &pXP, DT_SINGLELINE | DT_LEFT); //See which way Player is facing and draw it. switch(Player.facing) { case 1://North Draw("Data/Player/Stop/sN0.bmp", testX, testY, 96, 96); break; case 2://East Draw("Data/Player/Stop/sE0.bmp", testX, testY, 96, 96); break; case 3://South Draw("Data/Player/Stop/sS0.bmp", testX, testY, 96, 96); break; case 4://West Draw("Data/Player/Stop/sW0.bmp", testX, testY, 96, 96); break; } EndPaint(hwnd, &ps); } break; default: /* for messages that we don't deal with */ return DefWindowProc (hwnd, message, wParam, lParam); } return 0;}void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey) //Basic draw{ HINSTANCE hDraw = hThisInstance; //Draw instance HDC hDCdrawOFF = CreateCompatibleDC( GetDC(hwnd) ); //Create backbuffer CreateCompatibleBitmap( hDCdrawOFF, sizex, sizey ); HDC hDCdraw = GetDC(hwnd); //Create backbuffer DC hDCdraw = BeginPaint(hwnd, &ps); //Start paint with backbuffer DC HANDLE draw = LoadImage( hDraw, FileName, IMAGE_BITMAP, sizex, sizey, LR_LOADFROMFILE | LR_CREATEDIBSECTION ); //Load BMP SelectObject(hDCdrawOFF, draw); //Assign BMP to backbuffer GetObject( draw, sizeof(BITMAP), NULL ); //Get BMP BitBlt( GetDC(hwnd), x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY); //Draw to window //Cleanup ReleaseDC( hwnd, hDCdrawOFF); ReleaseDC( hwnd, hDCdraw ); DeleteDC( hDCdrawOFF); DeleteDC( hDCdraw); DeleteObject( draw ); EndPaint(hwnd, &ps); //End paint}void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey, bool timer, int time) //Draw with delay{ HINSTANCE hDraw = hThisInstance; HDC hDCdraw = GetDC(hwnd); HANDLE draw = LoadImage( hDraw, FileName, IMAGE_BITMAP, sizex, sizey, LR_LOADFROMFILE | LR_CREATEDIBSECTION ); HDC hDCdrawOFF = CreateCompatibleDC( GetDC(hwnd) ); CreateCompatibleBitmap( hDCdrawOFF, sizex, sizey ); hDCdraw = BeginPaint(hwnd, &ps); //Start paint with backbuffer DC SelectObject(hDCdrawOFF, draw); GetObject( draw, sizeof(BITMAP), NULL ); if(timer) { double Counter = InitTimer(); //Start Timer Counter = CurrentTime(); //Start counting time if (Counter < time) //If time not passed by Counter = CurrentTime(); //Update time else BitBlt( GetDC(hwnd), x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY); //If time gone by, draw BMP } //Cleanup ReleaseDC( hwnd, hDCdrawOFF); ReleaseDC( hwnd, hDCdraw ); DeleteDC( hDCdrawOFF); DeleteDC( hDCdraw); DeleteObject( draw ); EndPaint(hwnd, &ps); //End paint}void Init(){ //Initialize new game variable if not loaded Player.health = 100; Player.attack = 10; Player.level = 1; Player.xp = 0; Player.mana = 20; Player.dead = false; InvalidateRect(hwnd,NULL,FALSE);}void eInit(int dNum) //Create demon{ switch(dNum) { case 1: //Easiet Demon.health = 15; Demon.attack = 5; Demon.xp = 50; Demon.dead = false; break; case 2: //Medium Demon.health = 45; Demon.attack = 15; Demon.xp = 75; Demon.dead = false; break; case 3: //Hardest Demon.health = 80; Demon.attack = 45; Demon.xp = 100; Demon.dead = false; break; }}void save() //Save stats{ saveL(); saveX(); saveH(); saveA(); saveM();}void load() //Load stats{ loadL(); loadX(); loadH(); loadA(); loadM();}void saveL(){ myFile = fopen("Data/L.svg","w+b"); //Open/Create Level save fwrite(&Player.level, sizeof(int), 1, myFile); //Write Player Level fclose(myFile); //Close Level save}void loadL(){ myFile = fopen("Data/L.svg","r+b"); //Open Level save fread(&Player.level, sizeof(int), 1, myFile); //Read in data fclose(myFile); //Close Level save}void saveX(){ myFile = fopen("Data/X.svg","w+b"); //XP save fwrite(&Player.xp, sizeof(int), 1, myFile); fclose(myFile);}void loadX(){ myFile = fopen("Data/X.svg","r+b"); //XP save fread(&Player.xp, sizeof(int), 1, myFile); fclose(myFile);}void saveH(){ myFile = fopen("Data/H.svg","w+b"); //Health save fwrite(&Player.health, sizeof(int), 1, myFile); fclose(myFile);}void loadH(){ myFile = fopen("Data/H.svg","r+b"); //Health save fread(&Player.health, sizeof(int), 1, myFile); fclose(myFile);}void saveA(){ myFile = fopen("Data/A.svg","w+b"); //Attack save fwrite(&Player.attack, sizeof(int), 1, myFile); fclose(myFile);}void loadA(){ myFile = fopen("Data/A.svg","r+b"); //Attack save fread(&Player.attack, sizeof(int), 1, myFile); fclose(myFile);}void saveM(){ myFile = fopen("Data/M.svg","w+b"); //Mana save fwrite(&Player.mana, sizeof(int), 1, myFile); fclose(myFile);}void loadM(){ myFile = fopen("Data/M.svg","r+b"); //Mana save fread(&Player.mana, sizeof(int), 1, myFile); fclose(myFile);}void Attack(bool player){ if (!player) //If not attacking player Demon.health = (Demon.health - Player.attack); //Update Demon Health if(Demon.health <= 0) //If less than or equal to 0 { Demon.health = 0; //Health equals 0 Demon.dead = true; //Set flag Demon Died } else if (player) //If attacking player Player.health = (Player.health - Demon.attack); //Update Player Health if (Player.health <= 0) { Player.health = 0; Player.dead = true; }}void AttackE() //Attack east{ Draw( "Data/Player/Attack/aE0.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE1.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE2.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE3.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE4.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE5.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE6.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE7.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE8.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE9.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE10.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE11.bmp", testX, testY, 96, 96, true, aDelay); Draw( "Data/Player/Attack/aE12.bmp", testX, testY, 96, 96, true, aDelay);}void LevelUp(int nLevel){ switch(nLevel) { case 2: Player.health = 110; Player.mana = 30; Player.attack = 15; Player.level = 2; break; case 3: Player.health = 125; Player.mana = 45; Player.attack = 25; Player.level = 3; break; case 4: Player.health = 140; Player.mana = 60; Player.attack = 45; Player.level = 4; break; case 5: Player.health = 185; Player.mana = 70; Player.attack = 60; Player.level = 5; break; case 6: Player.health = 200; Player.mana = 85; Player.attack = 70; Player.level = 6; break; }}double InitTimer() //Start Timer{ __int64 time; QueryPerformanceFrequency((LARGE_INTEGER*)&TimeFrequency); QueryPerformanceCounter((LARGE_INTEGER*)&time); TimeBegin = (double)time / TimeFrequency; return TimeBegin;}double CurrentTime() //Get time{ __int64 time; QueryPerformanceCounter((LARGE_INTEGER*)&time); return ((double)time / TimeFrequency) - TimeBegin;}
And here is my heade file
Main.h
#include <windows.h>#include <time.h>#include <fstream>#include "resource.h"bool moving = false;bool attack = false;COLORREF BG = RGB(106, 76, 48); //BrownCOLORREF Black = RGB(0, 0, 0); //BlackCOLORREF TXT = RGB(0, 255, 0); //Neon green__int64 TimeFrequency;double TimeBegin;int testX = 100; //Player Xint testY = 0; //Player Yint testS = 96; //Player sizeint speed = 2;int delay = 500;int aDelay = 1000;HINSTANCE hThisInstance;HDC hdc;PAINTSTRUCT ps;RECT screen;RECT stats;RECT pHealth;RECT pMana;RECT pAttack;RECT pLevel;RECT pXP;TCHAR Phealth[64];TCHAR Pmana[64];TCHAR Pattack[64];TCHAR Plevel[64];TCHAR Pxp[64];FILE* myFile;HWND hwnd;void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey);void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey, bool timer, int time);void Init();void eInit(int dNum);void save();void load();void saveL();void loadL();void saveX();void loadX();void saveH();void loadH();void saveN();void loadN();void saveA();void loadA();void saveM();void loadM();void Attack(bool player = false);void AttackE(); //Attack Eastvoid LevelUp(int nLevel);double InitTimer();double CurrentTime();typedef struct sPlayer { int mana; int health; int attack; int xp; int level; bool dead; int facing; //1 for up, 2 for right, 3 for down, 4 for left };typedef struct sEnemy { int health; //HP int attack; //Attack power bool dead; //Dead flag int xp; //XP given };
I would appreciate any comments. About the code, new code, or anything else. Thanks everyone.
Please help me. GDI is hard, but a good learing experience.
I recommend that you dont use QueryPerformanceCounter(). If I understand it correctly, this will cause strange results on both laptops and multiprocessor/multicore systems. Each processor or core might have a different counter frequency and on laptops this frequency might change with power consumption. If you want to get a higher resolution than WM_TIMER try using timeGetTime().
Also, in your switch, rather than 0x41 you can just use the character literal 'A'. The character literal has a numeric value of 0x41 and makes your code much easier to understand.
Further, do not use BeginPaint() and EndPaint() outside of WM_PAINT or more than once inside WM_PAINT. For your Draw() function, just pass in the HDC returned by BeginPaint() rather than calling BeginPaint() yourself inside that function.
Finally, when using SelectObject() remember to save the return value in some other variable. Before you destroy a DC you must select the original objects back into the DC. SelectObject() returns the object that is being pushed out of the DC. In Draw() you select the "draw" bitmap into hDCdrawOFF but never select the original bitmap back in. This might be part of your leak.
Another part is probably in this line:
HDC hDCdrawOFF = CreateCompatibleDC( GetDC(hwnd) );
You're never releasing the DC associated with that GetDC() call. Yes, I know that you call ReleaseDC() on hDCdrawOFF but since hDCdrawOFF did not come from GetDC() this call to ReleaseDC() is incorrect. Get rid of that call to ReleaseDC() and change that line to
HDC hDCdrawOFF = CreateCompatibleDC( hDCdraw );
Another part is due to the fact that you have these lines as well
HDC hDCdraw = GetDC(hwnd); //Create backbuffer DC
hDCdraw = BeginPaint(hwnd, &ps); //Start paint with backbuffer DC
Ignoring the fact that this is the second call to BeginPaint(), you are losing the handle to the call to GetDC() since you are overwriting it with the return value to BeginPaint(). This is another DC that is leaked. Rather than do either of these, make hDCdraw a parameter to the function and pass in the DC you get from BeginPaint() from WM_PAINT.
Another DC leak comes from this line:
BitBlt( GetDC(hwnd), x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY);
Again, you are losing the handle to the DC that you got from GetDC(). Use hDCdraw here instead.
That's all I could see for now.
Also, in your switch, rather than 0x41 you can just use the character literal 'A'. The character literal has a numeric value of 0x41 and makes your code much easier to understand.
Further, do not use BeginPaint() and EndPaint() outside of WM_PAINT or more than once inside WM_PAINT. For your Draw() function, just pass in the HDC returned by BeginPaint() rather than calling BeginPaint() yourself inside that function.
Finally, when using SelectObject() remember to save the return value in some other variable. Before you destroy a DC you must select the original objects back into the DC. SelectObject() returns the object that is being pushed out of the DC. In Draw() you select the "draw" bitmap into hDCdrawOFF but never select the original bitmap back in. This might be part of your leak.
Another part is probably in this line:
HDC hDCdrawOFF = CreateCompatibleDC( GetDC(hwnd) );
You're never releasing the DC associated with that GetDC() call. Yes, I know that you call ReleaseDC() on hDCdrawOFF but since hDCdrawOFF did not come from GetDC() this call to ReleaseDC() is incorrect. Get rid of that call to ReleaseDC() and change that line to
HDC hDCdrawOFF = CreateCompatibleDC( hDCdraw );
Another part is due to the fact that you have these lines as well
HDC hDCdraw = GetDC(hwnd); //Create backbuffer DC
hDCdraw = BeginPaint(hwnd, &ps); //Start paint with backbuffer DC
Ignoring the fact that this is the second call to BeginPaint(), you are losing the handle to the call to GetDC() since you are overwriting it with the return value to BeginPaint(). This is another DC that is leaked. Rather than do either of these, make hDCdraw a parameter to the function and pass in the DC you get from BeginPaint() from WM_PAINT.
Another DC leak comes from this line:
BitBlt( GetDC(hwnd), x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY);
Again, you are losing the handle to the DC that you got from GetDC(). Use hDCdraw here instead.
That's all I could see for now.
YES!!! This worked. Now I have smooth animation(Except for the first step). I also have no more drawing memory leak. I have a leak when I post a message box, but thats it.
There's only two problems now.
1. When I take my first step, I stop, but then continue. I can't figure out how to flag if I'm moving without having that stop. Please help! I'm pulling my hair out!!!
2. I can't set the boundries so the player doesn't go out of sight. I know. A noob question. But I am a noob. Please help.
Here is my code.
main.h
And
main.cpp
Also, how would I draw text above the Player at any time with DrawTxt?
Thanks for your help. Peace
There's only two problems now.
1. When I take my first step, I stop, but then continue. I can't figure out how to flag if I'm moving without having that stop. Please help! I'm pulling my hair out!!!
2. I can't set the boundries so the player doesn't go out of sight. I know. A noob question. But I am a noob. Please help.
Here is my code.
main.h
#include <windows.h>#include <time.h>#include <fstream>#include "resource.h"bool moving = false;bool attack = false;COLORREF BG = RGB(106, 76, 48); //BrownCOLORREF Black = RGB(0, 0, 0); //BlackCOLORREF TXT = RGB(0, 255, 0); //Neon green__int64 TimeFrequency; //For Timer functionsdouble TimeBegin;int testX = 100; //Player Xint testY = 0; //Player Yint mX;int mY;int testS = 96; //Player sizeint speed = 4;int delay = 35;int aDelay = 0;HINSTANCE hThisInstance;HDC hdc;PAINTSTRUCT ps;RECT screen;RECT stats;RECT pHealth;RECT pMana;RECT pAttack;RECT pLevel;RECT pXP;TCHAR Dhealth[64];TCHAR Phealth[64];TCHAR Pmana[64];TCHAR Pattack[64];TCHAR Plevel[64];TCHAR Pxp[64];FILE* myFile; //For loading & savingHWND hwnd;void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey);void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey, bool timer, int time);void DrawTxt(TCHAR Text[64]);void Init(); //Init Playervoid eInit(int dNum); //Init Demonvoid save();void load();void saveL();void loadL();void saveX();void loadX();void saveH();void loadH();void saveN();void loadN();void saveA();void loadA();void saveM();void loadM();void Attack(bool player = false);void AttackE(); //Attack Eastvoid WalkE(); //Walk Eastvoid WalkN();void WalkS();void WalkW();void LevelUp(int nLevel);double InitTimer();double CurrentTime();typedef struct sPlayer { int mana; int health; int attack; int xp; int level; bool dead; int facing; //1 for up, 2 for right, 3 for down, 4 for left };typedef struct sEnemy { int health; //HP int attack; //Attack power bool dead; //Dead flag int xp; //XP given };
And
main.cpp
#include "main.h"/* Declare Windows procedure */LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);/* Make the class name into a global variable */char szClassName[ ] = "GOH";sPlayer Player;sEnemy Demon;int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) /* This is the handle for our window */{ MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = 0; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (hThisInstance, MAKEINTRESOURCE(GOH_ICON)); wincl.hIconSm = LoadIcon (hThisInstance, MAKEINTRESOURCE(GOH_ICON)); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = CreateSolidBrush(BG);; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "Gates of Heaven", /* Title Text */ WS_MINIMIZEBOX | WS_SYSMENU, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 900, /* The programs width */ 600, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ NULL, /* No menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow (hwnd, nFunsterStil); /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } /* The program return-value is 0 - The value that PostQuitMessage() gave */ return messages.wParam;}/* This function is called by the Windows function DispatchMessage() */LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) /* handle the messages */ { case WM_CLOSE: if(MessageBox( hwnd, "Do you want to save your current progress before you exit?", "Save Current Progress?", MB_YESNO | MB_ICONQUESTION) == IDYES) save(); case WM_DESTROY: PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; case WM_CREATE: if(MessageBox( hwnd, "Do you want to load your saved game?", "Load Save?", MB_YESNO | MB_ICONQUESTION) == IDYES) load(); else Init(); SetRect( &pHealth, 0, 0, 100, 20 ); SetRect( &pMana, 0, 30, 100, 50 ); SetRect( &pAttack, 0, 60, 100, 80); SetRect( &pLevel, 0, 90, 100, 120); SetRect( &pXP, 0, 120, 100, 160); Player.facing = 2; //Facing east break; case WM_MOUSEMOVE: break; case WM_KEYUP: switch(wParam) { case VK_F1: if(MessageBox( hwnd, "Are you sure that you want to save your current progress?", "Save Game?", MB_YESNO | MB_ICONQUESTION) == IDYES) { save(); } else return (1); break; case 0x41: //A while (!Demon.dead) { attack = true; AttackE(); Attack(false); Attack(true); } if(Demon.dead) { if(attack) { Player.xp = Player.xp + Demon.xp; InvalidateRect(hwnd,NULL,TRUE); } attack = false; eInit(1); } if(Player.xp == 1000) { LevelUp(2); InvalidateRect(hwnd,NULL,TRUE); } else if(Player.xp == 2000) { LevelUp(3); InvalidateRect(hwnd,NULL,TRUE); } else if(Player.xp == 3000) { LevelUp(4); InvalidateRect(hwnd,NULL,TRUE); } else if(Player.xp == 4000) { LevelUp(5); InvalidateRect(hwnd,NULL,TRUE); } else if(Player.xp == 5000) { LevelUp(6); InvalidateRect(hwnd,NULL,TRUE); } break; case 0x48: MessageBox(hwnd, "TEST", "TEST", MB_OK); break; case 0x4E: //N if(MessageBox( hwnd, "Are you sure that you want to start a new game and lose your current progress?", "New Game?", MB_YESNO | MB_ICONQUESTION) == IDYES) { Init(); InvalidateRect(hwnd,NULL,TRUE); } else return (1); break; case 0x4C: //L if(MessageBox( hwnd, "Are you sure that you want to load and lose your current progress?", "Load?", MB_YESNO | MB_ICONQUESTION) == IDYES) { load(); InvalidateRect(hwnd,NULL,TRUE); } else return (1); break; case VK_ESCAPE: if(MessageBox( hwnd, "Do you want to save your current progress before you exit?", "Save Current Progress?", MB_YESNO | MB_ICONQUESTION) == IDYES) save(); ReleaseDC(hwnd, hdc); DeleteDC(hdc); PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; case VK_UP: moving = false; break; case VK_DOWN: moving = false; break; case VK_LEFT: moving = false; break; case VK_RIGHT: moving = false; break; } break; case WM_KEYDOWN: switch(wParam) { case VK_UP: moving = true; Player.facing = 1; InvalidateRect(hwnd,NULL,FALSE); break; case VK_DOWN: moving = true; Player.facing = 3; InvalidateRect(hwnd,NULL,FALSE); break; case VK_LEFT: moving = true; Player.facing = 4; //Move left InvalidateRect(hwnd,NULL,FALSE); break; case VK_RIGHT: Player.facing = 2; moving = true; InvalidateRect(hwnd,NULL,FALSE); break; } break; case WM_PAINT: wsprintf(Phealth,"Health: %d", Player.health); wsprintf(Pmana,"Mana: %d", Player.mana); wsprintf(Pattack, "Attack: %d", Player.attack); wsprintf(Plevel,"Level: %d", Player.level); wsprintf(Pxp, "XP: %d", Player.xp); hdc = BeginPaint(hwnd, &ps); SetBkMode(hdc, TRANSPARENT); SetTextColor( hdc, TXT ); if(Player.dead) { GetClientRect (hwnd, &screen); FillRect(hdc, &screen, CreateSolidBrush(BG)); DrawText( hdc, "YOU DIED!!!", -1, &screen, DT_SINGLELINE | DT_CENTER | DT_VCENTER ); EndPaint(hwnd, &ps); DeleteObject( &screen ); } else if (!Player.dead) { //Draw stats DrawText(hdc, Phealth, -1, &pHealth, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Pmana, -1, &pMana, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Pattack, -1, &pAttack, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Plevel, -1, &pLevel, DT_SINGLELINE | DT_LEFT); DrawText(hdc, Pxp, -1, &pXP, DT_SINGLELINE | DT_LEFT); //See which way Player is facing and draw it. if(!moving) { switch(Player.facing) { case 1://North Draw("Data/Player/Stop/sN0.bmp", testX, testY, 96, 96); break; case 2://East Draw("Data/Player/Stop/sE0.bmp", testX, testY, 96, 96); break; case 3://South Draw("Data/Player/Stop/sS0.bmp", testX, testY, 96, 96); break; case 4://West Draw("Data/Player/Stop/sW0.bmp", testX, testY, 96, 96); break; } } if(moving) { switch(Player.facing) { case 1://North WalkN(); break; case 2://East WalkE(); break; case 3://South WalkS(); break; case 4://West if(testX != (900 - 96)) //If not leaving screen WalkW(); break; } } EndPaint(hwnd, &ps); DeleteObject(Phealth); DeleteObject(Pmana); DeleteObject(Pattack); DeleteObject(Plevel); DeleteObject(Pxp); ReleaseDC(hwnd,hdc); DeleteDC(hdc); } break; default: /* for messages that we don't deal with */ return DefWindowProc (hwnd, message, wParam, lParam); } return 0;}void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey) //Basic draw{ HINSTANCE hDraw = hThisInstance; //Draw instance HDC hDCdraw = GetDC(hwnd); //Create backbuffer DC HDC hDCdrawOFF = CreateCompatibleDC( hDCdraw ); //Create backbuffer HANDLE draw = LoadImage( hDraw, FileName, IMAGE_BITMAP, sizex, sizey, LR_LOADFROMFILE | LR_CREATEDIBSECTION ); //Load BMP SelectObject(hDCdrawOFF, draw); //Assign BMP to backbuffer GetObject( draw, sizeof(BITMAP), NULL ); //Get BMP BitBlt( hDCdraw, x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY); //Draw to window //Cleanup ReleaseDC( hwnd, hDCdrawOFF); ReleaseDC( hwnd, hDCdraw ); DeleteDC( hDCdrawOFF); DeleteDC( hDCdraw); DeleteObject( draw ); DeleteObject( hDraw ); DeleteObject( hDCdraw ); DeleteObject( hDCdrawOFF );}void Draw(LPCTSTR FileName, int x, int y, int sizex, int sizey, bool timer, int time) //Draw with delay{ HINSTANCE hDraw = hThisInstance; HDC hDCdraw = GetDC(hwnd); HANDLE draw = LoadImage( hDraw, FileName, IMAGE_BITMAP, sizex, sizey, LR_LOADFROMFILE | LR_CREATEDIBSECTION ); HDC hDCdrawOFF = CreateCompatibleDC( hDCdraw ); SelectObject(hDCdrawOFF, draw); GetObject( draw, sizeof(BITMAP), NULL ); if(timer) { double Counter = timeGetTime(); //Start Timer if (Counter < time) //If time not passed by Counter = timeGetTime(); //Update time else BitBlt( hDCdraw, x, y, sizex, sizey, hDCdrawOFF, 0, 0, SRCCOPY); //If time gone by, draw BMP } //Cleanup ReleaseDC( hwnd, hDCdrawOFF); ReleaseDC( hwnd, hDCdraw ); DeleteDC( hDCdrawOFF); DeleteDC( hDCdraw); DeleteObject( draw ); DeleteObject( hDraw );}void Init(){ //Initialize new game variable if not loaded Player.health = 100; Player.attack = 10; Player.level = 1; Player.xp = 0; Player.mana = 20; Player.dead = false; InvalidateRect(hwnd,NULL,FALSE);}void eInit(int dNum) //Create demon{ switch(dNum) { case 1: //Easiet Demon.health = 15; Demon.attack = 5; Demon.xp = 25; Demon.dead = false; break; case 2: //Medium Demon.health = 45; Demon.attack = 15; Demon.xp = 50; Demon.dead = false; break; case 3: //Hardest Demon.health = 80; Demon.attack = 45; Demon.xp = 100; Demon.dead = false; break; }}void save() //Save stats{ saveL(); saveX(); saveH(); saveA(); saveM();}void load() //Load stats{ loadL(); loadX(); loadH(); loadA(); loadM();}void saveL(){ myFile = fopen("Data/L.svg","w+b"); //Open/Create Level save fwrite(&Player.level, sizeof(int), 1, myFile); //Write Player Level fclose(myFile); //Close Level save DeleteObject( myFile );}void loadL(){ myFile = fopen("Data/L.svg","r+b"); //Open Level save fread(&Player.level, sizeof(int), 1, myFile); //Read in data fclose(myFile); //Close Level save DeleteObject( myFile );}void saveX(){ myFile = fopen("Data/X.svg","w+b"); //XP save fwrite(&Player.xp, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void loadX(){ myFile = fopen("Data/X.svg","r+b"); //XP save fread(&Player.xp, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void saveH(){ myFile = fopen("Data/H.svg","w+b"); //Health save fwrite(&Player.health, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void loadH(){ myFile = fopen("Data/H.svg","r+b"); //Health save fread(&Player.health, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void saveA(){ myFile = fopen("Data/A.svg","w+b"); //Attack save fwrite(&Player.attack, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void loadA(){ myFile = fopen("Data/A.svg","r+b"); //Attack save fread(&Player.attack, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void saveM(){ myFile = fopen("Data/M.svg","w+b"); //Mana save fwrite(&Player.mana, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void loadM(){ myFile = fopen("Data/M.svg","r+b"); //Mana save fread(&Player.mana, sizeof(int), 1, myFile); fclose(myFile); DeleteObject( myFile );}void Attack(bool player){ if (!player) //If not attacking player Demon.health = (Demon.health - Player.attack); //Update Demon Health if(Demon.health <= 0) //If less than or equal to 0 { Demon.health = 0; //Health equals 0 Demon.dead = true; //Set flag Demon Died } else if (player) //If attacking player Player.health = (Player.health - Demon.attack); //Update Player Health if (Player.health <= 0) { Player.health = 0; Player.dead = true; }}void AttackE() //Attack east{ Sleep(delay); Draw( "Data/Player/Attack/aE0.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE1.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE2.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE3.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE4.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE5.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE6.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE7.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE8.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE9.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE10.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE11.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); Draw( "Data/Player/Attack/aE12.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay);}void WalkE(){ Draw( "Data/Player/Walk/wE0.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE1.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE2.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE3.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE4.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE5.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE6.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); Draw( "Data/Player/Walk/wE7.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX + speed); moving = false;}void WalkN(){ moving = false; Draw( "Data/Player/Walk/wN0.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN1.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN2.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN3.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN4.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN5.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN6.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); Draw( "Data/Player/Walk/wN7.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY - speed); moving = false;}void WalkS(){ moving = false; Draw( "Data/Player/Walk/wS0.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS1.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS2.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS3.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS4.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS5.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS6.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); Draw( "Data/Player/Walk/wS7.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testY = (testY + speed); moving = false;}void WalkW(){ moving = false; testX = (testX - speed); Draw( "Data/Player/Walk/wW0.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW1.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW2.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW3.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW4.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW5.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW6.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay); testX = (testX - speed); Draw( "Data/Player/Walk/wW7.bmp", testX, testY, 96, 96, true, aDelay); Sleep(delay);}void LevelUp(int nLevel){ switch(nLevel) { case 2: Player.health = 110; Player.mana = 30; Player.attack = 15; Player.level = 2; break; case 3: Player.health = 125; Player.mana = 45; Player.attack = 25; Player.level = 3; break; case 4: Player.health = 140; Player.mana = 60; Player.attack = 45; Player.level = 4; break; case 5: Player.health = 185; Player.mana = 70; Player.attack = 60; Player.level = 5; break; case 6: Player.health = 200; Player.mana = 85; Player.attack = 70; Player.level = 6; break; }}void DrawTxt(TCHAR Text[64]){ RECT test; SetRect( &test, 200, 0, 300, 30 ); DrawText(hdc, Text, -1, &test, DT_SINGLELINE | DT_LEFT);}
Also, how would I draw text above the Player at any time with DrawTxt?
Thanks for your help. Peace
You are still leaking
For example, you are leaking a brush with this line:
FillRect(hdc, &screen, CreateSolidBrush(BG));
You should do something like this
HBRUSH hBrush = CreateSolidBrush(BG);
FillRect(hdc, &screen, hBrush);
DeleteObject(hBrush);
It's also incorrect to call DeleteObject() on a RECT as you do in this line:
DeleteObject( &screen );
If you want to know when and how to release objects you should check the documentation for these objects on the MSDN. Check the documentation for the functions you use to create the objects and the MSDN will tell you how to properly destroy them. In general, however, if you get the object from a GDI function beginning with "Create" then you destroy the object using a function beginning with "Delete". If you get it from a function beginning with "Get" then you release it with a function beginning with "Release". If the type begins with an H then it is a handle and probably needs to be released. Types which dont begin with H usually dont need to be released. This includes TCHAR (which I see you calling DeleteObject() on as well). You also try to do this with a FILE. The proper way to close a file is with the function fclose(), which you do use. Only use DeleteObject() with types that require you to.
In Draw() you are still inproperly cleaning up. You need to remember the original bitmap that was in hDCdrawOFF. Change this line
SelectObject(hDCdrawOFF, draw);
To something like this
HBITMAP hOldBmp = (HBITMAP)SelectObject(hDCdrawOFF, draw);
... rest of your code ...
SelectObject(hDCdrawOFF, hOldBmp);
ReleaseDC( hwnd, hDCdraw );
DeleteDC( hDCdrawOFF);
DeleteObject( draw );
Before you delete a DC always return it to its original state. Also note that in your above code I removed the call to ReleaseDC() for hDCdrawOFF and the call to DeleteDC() for hDCdraw. hDCdrawOFF was created using CreateCompatibleDC() and so must be destroyed using DeleteDC() and hDCdraw was created using GetDC() and so must be destroyed using ReleaseDC().
That's all I could see for now.
1) When you take your first step you stop because the keyboard has a delay before it starts to send repeat WM_KEYDOWN messages. It might be better for you to create a timer and whenever that timer fires call your walk functions (see 2 for a suggestion on their improvement). When you get the appropriate WM_KEYUP message kill the timer. Look into the functions SetTimer() and KillTimer().
2) If you want to prevent the player from going out of site check his position before you update where he is. If his new position will be valid (that is, within the viewing area) then update his current position, otherwise do nothing. You can handle this in your walk functions.
Note, your walk functions are all very similar. I suggest finding a way to combine them into a single function. You might want to try something like
Walk(int how_far_horizontal, int how_far_vertical)
3) If you want to draw text above your player you need to know your text's height. To do that you can either use GetTextMetrics() or GetTextExtentPoint32(). I would probably choose GetTextMetrics().
For example, you are leaking a brush with this line:
FillRect(hdc, &screen, CreateSolidBrush(BG));
You should do something like this
HBRUSH hBrush = CreateSolidBrush(BG);
FillRect(hdc, &screen, hBrush);
DeleteObject(hBrush);
It's also incorrect to call DeleteObject() on a RECT as you do in this line:
DeleteObject( &screen );
If you want to know when and how to release objects you should check the documentation for these objects on the MSDN. Check the documentation for the functions you use to create the objects and the MSDN will tell you how to properly destroy them. In general, however, if you get the object from a GDI function beginning with "Create" then you destroy the object using a function beginning with "Delete". If you get it from a function beginning with "Get" then you release it with a function beginning with "Release". If the type begins with an H then it is a handle and probably needs to be released. Types which dont begin with H usually dont need to be released. This includes TCHAR (which I see you calling DeleteObject() on as well). You also try to do this with a FILE. The proper way to close a file is with the function fclose(), which you do use. Only use DeleteObject() with types that require you to.
In Draw() you are still inproperly cleaning up. You need to remember the original bitmap that was in hDCdrawOFF. Change this line
SelectObject(hDCdrawOFF, draw);
To something like this
HBITMAP hOldBmp = (HBITMAP)SelectObject(hDCdrawOFF, draw);
... rest of your code ...
SelectObject(hDCdrawOFF, hOldBmp);
ReleaseDC( hwnd, hDCdraw );
DeleteDC( hDCdrawOFF);
DeleteObject( draw );
Before you delete a DC always return it to its original state. Also note that in your above code I removed the call to ReleaseDC() for hDCdrawOFF and the call to DeleteDC() for hDCdraw. hDCdrawOFF was created using CreateCompatibleDC() and so must be destroyed using DeleteDC() and hDCdraw was created using GetDC() and so must be destroyed using ReleaseDC().
That's all I could see for now.
1) When you take your first step you stop because the keyboard has a delay before it starts to send repeat WM_KEYDOWN messages. It might be better for you to create a timer and whenever that timer fires call your walk functions (see 2 for a suggestion on their improvement). When you get the appropriate WM_KEYUP message kill the timer. Look into the functions SetTimer() and KillTimer().
2) If you want to prevent the player from going out of site check his position before you update where he is. If his new position will be valid (that is, within the viewing area) then update his current position, otherwise do nothing. You can handle this in your walk functions.
Note, your walk functions are all very similar. I suggest finding a way to combine them into a single function. You might want to try something like
Walk(int how_far_horizontal, int how_far_vertical)
3) If you want to draw text above your player you need to know your text's height. To do that you can either use GetTextMetrics() or GetTextExtentPoint32(). I would probably choose GetTextMetrics().
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement