Visual C++游戏编程基础之行为型AI游戏
2019-06-16 18:51
1706 查看
一、设计目标
1.建立一个回合制游戏,角色设定怪物与玩家,并在下方显示它们的生命值;
2.在背景图上贴上攻击标志,鼠标点击该标志时,玩家向怪物发动 攻击,并在左下角输出怪物的状态信息;
3.玩家回合结束后,轮到怪物,根据怪物的HP来决定要选择哪种攻击方式或者逃跑或重伤而死;
4.当某一方HP为0时,贴上游戏结束标志;
二、基本思路
1.初始化过程中,将背景图、怪物及其HP、玩家及其HP、攻击标志贴到mdc,最后在贴到hdc;
2.单击左键,WndProc函数处理该消息,获取光标位置判断是否在攻击标志范围内,有就将attack设为true;
3.接着回到MyPaint函数,玩家开始攻击,用f来表示贴图的次数,将攻击图像贴在怪物身上持续6个画面,然后f更新到第10个画
面时,降低怪物的HP,并把伤害输出到左下角的文本框,并检查怪物的状态;
4.当f更新到第15个画面时,这次是怪物的回合,设定若怪物HP>20,有90%几率发动普通攻击,10%的几率发动魔法攻击,HP
低于20就有5种情况:普攻、魔攻、全力攻、回血、逃跑,各有20%几率;
5.f更新到26个画面时,根据怪物的选择进行贴图,持续5个画面,当f更新到30时,减少玩家的HP并输出其状态到左下角,或者
因血量太低逃跑或死亡;
6.一个回合结束,f重新设为0,等待下一回合,直到over=true,触发游戏结束标志;
三、效果
四、代码如下
[code] #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; }
相关文章推荐
- MMORPG大型游戏设计与开发(服务器 AI 基础接口)
- 游戏中的 AI 学习笔记(数学基础--矢量)
- 游戏AI基础
- < Unity 3D专栏 >游戏中 - 怪物AI基础篇
- 021 VS2013 C++ 行为型游戏AI
- Visual C++游戏编程基础之游戏循环
- 游戏AI之行为树(下)
- 游戏开发基础(3)
- AI数学基础(1)--- 马尔可夫不等式
- 推荐一本3D基础的书----《3D数学基础图形与游戏开发》
- unity基础开发----unity游戏速度更快的简易检查表
- 游戏开发基础(六)
- AI大牛Jerry Kaplan:AGI?没有技术和工程基础
- 【Visual C++】游戏开发笔记十七 游戏基础算法(一) 游戏随机系统初步
- 【读书笔记《Android游戏编程之从零开始》】10.游戏开发基础(View 游戏框架)
- Unity3D 之3D游戏SD快打 3D游戏基础入门开发全(1)
- 3D Math Primer for Graphics and Game Development -- 图形与游戏开发(3D数学基础) (简介)
- 信息安全系统设计基础课程实践:简单TUI游戏设计
- 【bzoj1610】[Usaco2008 Feb]Line连线游戏 计算几何基础
- 【阅读笔记之三】《DIRECTX.9.0.3D游戏开发编程基础》:Direct3D初始化