First, the design goal
1. Establish a turn-based games, role players and monsters set, and show them the value of life at the bottom;
2. Paste attack flag on the background, the mouse click on the logo, the player to launch attacks monster, and the monster at the bottom left of the output status information;
3. After the player's turn, turn the monster, to decide which way to choose to attack or escape serious injury or death according to the monsters of HP;
4. When HP is either 0, affix marks the end of the game;
Second, the basic idea
1. initialization process, the background image, monsters and HP, the players and their HP, attack signs affixed to the mdc, finally stick to hdc;
2. Click the left, the WndProc function processes the message, acquires the cursor position in the mark, determines whether the attack range, the attack will be set true;
3. Then return to MyPaint function, players began to attack, often expressed by f maps will attack the image posted last six screen monster, then f updated to 10th painting
When the face, decrease the HP monster, and outputs the damage to the lower left corner of the text box, and check the status monster;
4. When the update to f 15 pictures, this is the monster's turn, if set monster HP> 20, 90% chance to launch a normal attack, 10% chance to launch magic attacks, HP
Below 20 there are five kinds of situations: Pugong, Mo Gong, to attack, the return of blood to escape, each with a 20% probability;
When 5.f 26 to update the screen, according to the map selected monster for five pictures, when f 30 is updated to reduce the player's HP and outputs the state to the lower-left corner, or
Because the blood is too low to escape or death;
6. One end of the round, f reset to 0, wait for the next round, until over = true, the trigger mark the end of the game;
Third, the effect
Four, as follows
#include "stdafx.h"
#include <stdio.h>
//结构体:储存怪物或玩家的状态信息
struct chr
{
int nHp;//目前生命值
int fHp;//最大生命值
int lv;//等级
int w;//加权值
int kind;//怪物的行为代号
};
//声明全局变量
HINSTANCE hInst;
HBITMAP bg,sheep,girl,skill,slash,magic,recover,game;//skill--攻击命令图;slash--普通攻击图;magic--怪物魔法攻击图;recover--怪物恢复魔法图;game--游戏结束图
HDC hdc,mdc,bufdc;
HWND hWnd;
DWORD tPre,tNow;
int pNum,f,txtNum;//pNum--玩家跑动图编号;f--每一回合攻击更新的画面数;TxtNum--记录目前所要显示消息的总数
bool attack,over;//attack记录玩家是否点击攻击命令;over一方生命值为0时,设为true
chr player,monster;
char text[5][100];//存储对战时要显示的消息
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void MyPaint(HDC hdc);
void MsgInsert(char*);//****新增要显示的消息到‘text’缓冲区,当显示的消息数目达到显示的上限数目时,删除最先的消息*********************************
void CheckDie(int hp,bool player);//每次攻击之后进行判断
void MyPaint1(HDC hdc,LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
tNow = GetTickCount();
if(tNow-tPre >= 40)
MyPaint(hdc);
}
}
return msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "canvas";
wcex.hIconSm = NULL;
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP bmp;
hInst = hInstance;
hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd,100,100,640,520,true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc,640,480);
SelectObject(mdc,bmp);
bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,640,480,LR_LOADFROMFILE);
sheep = (HBITMAP)LoadImage(NULL,"sheep.bmp",IMAGE_BITMAP,133,220,LR_LOADFROMFILE);
girl = (HBITMAP)LoadImage(NULL,"girl.bmp",IMAGE_BITMAP,480,148,LR_LOADFROMFILE);
skill = (HBITMAP)LoadImage(NULL,"skill.bmp",IMAGE_BITMAP,74,60,LR_LOADFROMFILE);
slash = (HBITMAP)LoadImage(NULL,"slash.bmp",IMAGE_BITMAP,196,162,LR_LOADFROMFILE);
magic = (HBITMAP)LoadImage(NULL,"magic.bmp",IMAGE_BITMAP,200,100,LR_LOADFROMFILE);
recover = (HBITMAP)LoadImage(NULL,"recover.bmp",IMAGE_BITMAP,300,150,LR_LOADFROMFILE);
game = (HBITMAP)LoadImage(NULL,"over.bmp",IMAGE_BITMAP,289,74,LR_LOADFROMFILE);
player.nHp = player.fHp = 50;
player.lv = 2;
player.w = 4;//设定攻击伤害加权值
monster.nHp = monster.fHp = 30;
monster.lv = 1;
monster.w = 1;
txtNum = 0;//显示消息数目
MyPaint(hdc);
return TRUE;
}
void MyPaint(HDC hdc)
{
char str[100];
int i,damage;
//贴上背景图
SelectObject(bufdc,bg);
BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);
//显示对战消息
for(i=0;i<txtNum;i++)
TextOut(mdc,0,360+i*20,text[i],strlen(text[i]));
//贴上怪物
if(monster.nHp>0)
{
SelectObject(bufdc,sheep);
BitBlt(mdc,70,180,133,110,bufdc,0,110,SRCAND);
BitBlt(mdc,70,180,133,110,bufdc,0,0,SRCPAINT);
sprintf(str,"%d / %d",monster.nHp,monster.fHp);
TextOut(mdc,100,320,str,strlen(str));
}
//贴上玩家
if(player.nHp>0)
{
SelectObject(bufdc,girl);
BitBlt(mdc,500,200,60,74,bufdc,pNum*60,74,SRCAND);
BitBlt(mdc,500,200,60,74,bufdc,pNum*60,0,SRCPAINT);
sprintf(str,"%d / %d",player.nHp,player.fHp);
TextOut(mdc,510,320,str,strlen(str));
}
if(over) //贴上游戏结束标志
{
SelectObject(bufdc,game);
BitBlt(mdc,200,200,289,37,bufdc,0,37,SRCAND);
BitBlt(mdc,200,200,289,37,bufdc,0,0,SRCPAINT);
}
else if(!attack) //贴上攻击标志
{
SelectObject(bufdc,skill);
BitBlt(mdc,500,350,74,30,bufdc,0,30,SRCAND);
BitBlt(mdc,500,350,74,30,bufdc,0,0,SRCPAINT);
}
else
{
f++; //递增变量,每回合开始重设为0;
//玩家按下攻击键时,玩家可看到6个画面(5~10)的攻击暂留效果
if(f>=5 && f<=10)
{
SelectObject(bufdc,slash);
BitBlt(mdc,100,160,98,162,bufdc,98,0,SRCAND);
BitBlt(mdc,100,160,98,162,bufdc,0,0,SRCPAINT);//在怪物身上贴上攻击特效
//第10个画面的时候,减少怪物的生命值
if(f == 10)
{
damage = rand()%10 + player.lv*player.w;
monster.nHp -= (int)damage;
sprintf(str," 怪物生命值减少%d HP ",damage);
MsgInsert(str);//text里的内容是从这里传递过去的
CheckDie(monster.nHp,false);//检查怪物是否还活着;flase表示要判断的对象是monster
}
}
srand(tPre);//产生随机数,若int固定,那么在rand下,它是伪随机数,要产生真正的随机数必须是个时刻变化的量
//回合开始后的第15个画面,判断怪物要采取何种行动
if(f == 15)
{
if(monster.nHp > 20)
{
if(rand()%10 != 1)
monster.kind = 0;//90%的几率进行普通攻击
else
monster.kind = 1;//10%的几率进行魔法攻击
}
else
{
switch(rand()%5)
{
case 0: //普通攻击
monster.kind = 0;
break;
case 1: //魔法攻击
monster.kind = 1;
break;
case 2: //全力攻击
monster.kind = 2;
break;
case 3: //补血
monster.kind = 3;
break;
case 4: //逃跑
monster.kind = 4;
break;
}
}
}
//第26~30个画面间,对怪物所作出的行为进行贴图操作
if(f>=26 && f<=30)
{
switch(monster.kind)
{
case 0: //普通攻击
SelectObject(bufdc,slash);
BitBlt(mdc,480,150,98,162,bufdc,98,0,SRCAND);
BitBlt(mdc,480,150,98,162,bufdc,0,0,SRCPAINT);
//到第30个画面,对玩家HP减掉普通攻击的部分
if(f == 30)
{
damage = rand()%10 + monster.lv*monster.w;
player.nHp -= (int)damage;
sprintf(str," 玩家生命值减少 %d HP ",damage);
MsgInsert(str);
CheckDie(player.nHp,true);
}
break;
case 1: //魔法攻击
SelectObject(bufdc,magic);
BitBlt(mdc,480,190,100,100,bufdc,100,0,SRCAND);
BitBlt(mdc,480,190,100,100,bufdc,0,0,SRCPAINT);
//到第30个画面,对玩家HP减掉魔法攻击的部分
if(f == 30)
{
damage = rand()%10 + 3*monster.w;
player.nHp -= (int)damage;
sprintf(str," 玩家的生命值减少%d HP ",damage);
MsgInsert(str);
CheckDie(player.nHp,true);
}
break;
case 2:
SelectObject(bufdc,slash);
BitBlt(mdc,480,150,98,162,bufdc,98,0,SRCAND);
BitBlt(mdc,480,150,98,162,bufdc,0,0,SRCPAINT);
//到第30个画面,对玩家HP减掉全力攻击的部分
if(f == 30)
{
damage = rand()%10 + monster.lv*monster.w*5;
player.nHp -= (int)damage;
sprintf(str," 玩家的生命值减少 %d HP ",damage);
MsgInsert(str);
CheckDie(player.nHp,true);
}
break;
case 3: //回血
SelectObject(bufdc,recover);
BitBlt(mdc,60,160,150,150,bufdc,150,0,SRCAND);
BitBlt(mdc,60,160,150,150,bufdc,0,0,SRCPAINT);
//更新到第30个画面的时候,怪物回血
if(f == 30)
{
monster.nHp += 30;
sprintf(str," 怪兽回血值为30 ",damage);
MsgInsert(str);
}
break;
case 4:
//更新到第30个画面,逃跑
if(f == 30)
{
if(rand()%3 == 1) //2/3的几率怪兽死亡,游戏结束
{
over = true;
monster.nHp = 0;
sprintf(str," 怪兽重伤而死! ");
MsgInsert(str);
}
else
{
sprintf(str," 怪兽已经逃跑! ");
MsgInsert(str);
}
}
break;
}
}
if(f == 30) //攻击回合结束,准备下一个回合
{
attack = false;
f = 0;
}
}
BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);
tPre = GetTickCount();
pNum++;
if(pNum == 8)
pNum = 0;
}
//****新增要显示的消息到‘text’缓冲区,当显示的消息数目达到显示的上限数目时,删除最先的消息*********************************
void MsgInsert(char* str)
{
if(txtNum < 5)
{
sprintf(text[txtNum],str);
txtNum++;
}
else
{
for(int i=0;i<txtNum;i++)//有5行的话,各行依次往上前进一行,最新的消息放在最后一行;
sprintf(text[i],text[i+1]);
sprintf(text[4],str);
}
}
//****检查玩家的生存情况*************************
void CheckDie(int hp,bool player)
{
char str[100];
if(hp <= 0)
{
over = true;
if(player)
{
sprintf(str," 玩家战败! ");
MsgInsert(str);
}
else
{
sprintf(str," 怪物战败! ");
MsgInsert(str);
}
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int x,y;
switch (message)
{
case WM_KEYDOWN:
if(wParam==VK_ESCAPE)
PostQuitMessage(0);
break;
case WM_LBUTTONDOWN: //检测攻击范围
if(!attack)
{
x = LOWORD(lParam);
y = HIWORD(lParam);
if(x >= 500 && x <= 574 && y >= 350 && y <= 380)
attack = true;
}
break;
case WM_DESTROY:
DeleteDC(mdc);
DeleteDC(bufdc);
DeleteObject(bg);
DeleteObject(sheep);
DeleteObject(girl);
DeleteObject(skill);
DeleteObject(slash);
DeleteObject(magic);
DeleteObject(recover);
DeleteObject(game);
ReleaseDC(hWnd,hdc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}