Visual C ++ game programming based on the behavior of AI-type game

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;
}

 

Guess you like

Origin blog.csdn.net/Sruggle/article/details/92415008