• Advertisement
Sign in to follow this  

bitmap animation with Timer???

This topic is 4246 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Advertisement
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

int main()
{
X.Animate();
}



void Class::Animate()
{
if(Counter < 1000)
{
++Counter;
return;
else
//next frame of animation
}


or using sleep it would just be

int 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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
As I said I would, here is my entire code, so maybe someone can find my 4KB memory leak. Please help. Thx.

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); //Brown
COLORREF Black = RGB(0, 0, 0); //Black
COLORREF TXT = RGB(0, 255, 0); //Neon green

__int64 TimeFrequency;
double TimeBegin;


int testX = 100; //Player X
int testY = 0; //Player Y
int testS = 96; //Player size
int 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 East
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
};





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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

#include <windows.h>
#include <time.h>
#include <fstream>
#include "resource.h"



bool moving = false;
bool attack = false;

COLORREF BG = RGB(106, 76, 48); //Brown
COLORREF Black = RGB(0, 0, 0); //Black
COLORREF TXT = RGB(0, 255, 0); //Neon green

__int64 TimeFrequency; //For Timer functions
double TimeBegin;


int testX = 100; //Player X
int testY = 0; //Player Y
int mX;
int mY;
int testS = 96; //Player size
int 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 & saving



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 DrawTxt(TCHAR Text[64]);

void Init(); //Init Player
void eInit(int dNum); //Init Demon
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 East
void WalkE(); //Walk East
void 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



Share this post


Link to post
Share on other sites
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().

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement