VC++2010游戏开发随记之十五

发布时间:2013-02-25 19:17:41   来源:文档文库   
字号:

 

Visual C++】游戏开发笔记十五 游戏人工智能运动型游戏AI

我们常常听闻AIArtificial Intelligence人工智能)这个名词,比如Dota里面的AI地图。写这篇文章的时候,最新版的Dota AI6.72f,估计过几天6.73AI也要出来了。很多Dota玩家喜欢玩AI地图练练感觉和补刀,可以这样说,Dota 地图成功的加入了AI元素,是近几年Dota风靡全球不可缺少的因素之一。

一、知识点讲解

那么,到底什么是AI呢?首先我们来了解一下人工智能(AI)的具体定义。人工智能Artificial Intelligence)简称AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。人工智能研究如何用计算机去模拟、延伸和扩展人的智能;如何把计算机用得更聪明;如何设计和建造具有高智能水平的计算机应用系统;如何设计和制造更聪明的计算机以及智能水平更高的智能计算机等。人工智能是计算机科学的一个分支,人工智能是计算机科学技术的前沿科技领域。人工智能与计算机软件有密切的关系。一方面,各种人工智能应用系统都要用计算机软件去实现,另一方面,许多聪明的计算机软件也应用了人工智能的理论方法和技术。

而我们要讲解的游戏人工智能,只是渊博的人工智能领域里面的冰山一角。我们不会用到那些类似于神经网络,基因算法,模糊逻辑等复杂的人工智能理论,我们只需利用自己本身的思考模式去赋予游戏中角色判断的能力,来进行某些特定的行为。

今天我们主角是运动型的AI,下面就开始正题吧。

凡是在游戏中会移动的物体,几乎都涉及到了运动型的游戏AI,例如游戏中怪物的追逐或者躲避玩家和游戏中NPC角色的移动都是移动型AI的例子。

<1>追逐移动

下面我们以移动型AI里的追逐移动型AI来作为例子讲解。

追逐移动一般是通过控制一角色朝某一目标接近来实现,简单点说,就是两个物体的空间坐标相互接近。比如我们要设计一个怪物追逐玩家的游戏,只要在每次进行贴图时,将怪物坐在坐标与玩家角色所在的坐标进行比较,自增或者自减怪物X,Y轴上的贴图坐标,就可产生追逐移动的效果。下面就是一个典型的怪物追逐外加的移动AI算法,其中枭兽X”枭兽Y”幻影刺客X”幻影刺客Y”分别用来表示怪物及玩家在XY轴上的贴图坐标。

【算法1

[cpp] view plaincopyprint?

1. If(枭兽X>幻影刺客X  

2. 枭兽X--  

3. else  

4. 枭兽X++  

5. If(枭兽Y<幻影刺客Y  

6. 枭兽Y++  

7. else  

8. 枭兽Y--  



下面我们再来看一个例子,这段算法是以上面的【算法1】为核心代码,赋予了怪物更多的思考空间。追逐移动的怪物会按照自身生命值的多寡来决定是否进行追逐,每次计算下次的位置坐标时,也只有二分之三的几率能正确地朝向玩家,以其中以枭兽HP”来表示怪物当前的生命值。

【算法2

[cpp] view plaincopyprint?

1. If(枭兽HP>200              //生命值大于200时才追  

2. (  

3. P=rand()%3;                   //取随机数除以3的余数  

4. If(p!=1)                        //余数不为1时进行追逐  

5. {  

6. If(枭兽X>幻影刺客X  

7. 枭兽X--  

8. else  

9. 枭兽X++  

10. If(枭兽Y<幻影刺客Y  

11. 枭兽Y++  

12. else  

13. 枭兽Y--  

14. }  

15. else  

16.     枭兽HP+=5           //怪物不动,自动补5点血  

17.   





这样的怪物就比较有灵性了,要继续创造出更聪明的AI,只要继续完善代码,写出更多的功能就行了。

<2>躲避移动

其实躲避移动和追逐移动的算法差不多,就是把++的地方和--对调就行了,让怪物与人物的空间坐标相互远离。

具体代码如下:

【算法3

[cpp] view plaincopyprint?

1. If(枭兽X>幻影刺客X  

2. 枭兽X++  

3. else  

4. 枭兽X--  

5. If(枭兽Y<幻影刺客Y  

6. 枭兽Y--  

7. else  

8. 枭兽Y++  





二、在实例中将知识融会贯通

依旧,我们看一个实例,来将本节的知识融会贯通。

这是一个小鸟追逐小女孩的场景,我们需要用键盘的【】【】【】【】键来躲避小鸟的追击,具体键盘输入消息的知识点还

不太了解的朋友,请移步笔记十二,这里给出链接:

Visual C++】游戏开发笔记十二 游戏输入消息处理(一) 键盘消息处理

下面依旧是贴图详细注释的源代码:

[cpp] view plaincopyprint?

1. #include "stdafx.h"  

2. #include   

3.   

4. //全局变量声明  

5. HINSTANCE hInst;  

6. HBITMAP girl[4],bg,bird;                  

7. HDC     hdc,mdc,bufdc;  

8. HWND    hWnd;  

9.   

10. DWORD   tPre,tNow,nowX,nowY;  

11. POINT   p[3];               //用于记录3只小鸟的贴图坐标  

12. int     num,dir,x,y;       //xy变量为人物贴图坐标,dir为人物移动方向,这里我们中以0123代表人物上,下,左,右方向上的移动:num为连续贴图中的小图编号  

13.   

14. //全局函数声明  

15. ATOM                MyRegisterClass(HINSTANCE hInstance);  

16. BOOL                InitInstance(HINSTANCEint);  

17. LRESULT CALLBACK    WndProc(HWNDUINTWPARAMLPARAM);  

18. void                MyPaint(HDC hdc);  

19.   

20. //****WinMain函数,程序入口点函数***********************  

21. int APIENTRY WinMain(HINSTANCE hInstance,  

22.                      HINSTANCE hPrevInstance,  

23.                      LPSTR     lpCmdLine,  

24.                      int       nCmdShow)  

25. {  

26.     MSG msg;  

27.   

28.     MyRegisterClass(hInstance);  

29.   

30.     //初始化  

31.     if (!InitInstance (hInstance, nCmdShow))   

32.     {  

33.         return FALSE;  

34.     }  

35.   

36.      GetMessage(&msg,NULL,NULL,NULL);            //初始化msg    

37.     //消息循环  

38.     while( msg.message!=WM_QUIT )  

39.     {  

40.         if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )  

41.         {  

42.             TranslateMessage( &msg );  

43.             DispatchMessage( &msg );  

44.         }  

45.         else  

46.         {  

47.             tNow = GetTickCount();  

48.             if(tNow-tPre >= 40)  

49.                 MyPaint(hdc);  

50.         }  

51.     }  

52.   

53.     return msg.wParam;  

54. }  

55.   

56. //****设计一个窗口类,类似填空题,使用窗口结构体*******************  

57. ATOM MyRegisterClass(HINSTANCE hInstance)  

58. {  

59.     WNDCLASSEX wcex;  

60.   

61.     wcex.cbSize = sizeof(WNDCLASSEX);   

62.     wcex.style          = CS_HREDRAW | CS_VREDRAW;  

63.     wcex.lpfnWndProc    = (WNDPROC)WndProc;  

64.     wcex.cbClsExtra     = 0;  

65.     wcex.cbWndExtra     = 0;  

66.     wcex.hInstance      = hInstance;  

67.     wcex.hIcon          = NULL;  

68.     wcex.hCursor        = NULL;  

69.     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);  

70.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  

71.     wcex.lpszMenuName   = NULL;  

72.     wcex.lpszClassName  = "canvas";  

73.     wcex.hIconSm        = NULL;  

74.   

75.     return RegisterClassEx(&wcex);  

76. }  

77.   

78. //****初始化函数*************************************  

79. // 加载位图并设定各种初始值  

80. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  

81. {  

82.     HBITMAP bmp;  

83.     hInst = hInstance;  

84.   

85.     hWnd = CreateWindow("canvas""浅墨的绘图窗口" , WS_OVERLAPPEDWINDOW,  

86.         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);  

87.   

88.     if (!hWnd)  

89.     {  

90.         return FALSE;  

91.     }  

92.   

93.     MoveWindow(hWnd,10,10,640,480,true);  

94.     ShowWindow(hWnd, nCmdShow);  

95.     UpdateWindow(hWnd);  

96.   

97.     hdc = GetDC(hWnd);  

98.     mdc = CreateCompatibleDC(hdc);  

99.     bufdc = CreateCompatibleDC(hdc);  

100.   

101.   

102.     //建立空的位图并置入mdc  

103.     bmp = CreateCompatibleBitmap(hdc,640,480);  

104.     SelectObject(mdc,bmp);  

105.   

106.   

107.     //设定人物贴图初始位置和移动方向  

108.     x = 300;  

109.     y = 250;  

110.     dir = 0;  

111.     num = 0;  

112.     nowX = 300;  

113.     nowY = 300;  

114.   

115.   

116.     //载入各连续移动位图及背景图  

117.     girl[0] = (HBITMAP)LoadImage(NULL,"girl0.bmp",IMAGE_BITMAP,440,148,LR_LOADFROMFILE);  

118.     girl[1] = (HBITMAP)LoadImage(NULL,"girl1.bmp",IMAGE_BITMAP,424,154,LR_LOADFROMFILE);  

119.     girl[2] = (HBITMAP)LoadImage(NULL,"girl2.bmp",IMAGE_BITMAP,480,148,LR_LOADFROMFILE);  

120.     girl[3] = (HBITMAP)LoadImage(NULL,"girl3.bmp",IMAGE_BITMAP,480,148,LR_LOADFROMFILE);  

121.     bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,640,480,LR_LOADFROMFILE);\  

122.   

123.   

124.     bird = (HBITMAP)LoadImage(NULL,"bird.bmp",IMAGE_BITMAP,122,122,LR_LOADFROMFILE);  

125.   

126.     p[0].x = 30;  

127.     p[0].y = 100;  

128.   

129.     p[1].x = 250;  

130.     p[1].y = 250;  

131.   

132.     p[2].x = 500;  

133.     p[2].y = 400;  

134.   

135.   

136.     MyPaint(hdc);  

137.   

138.     return TRUE;  

139. }  

140.   

141. //****自定义绘图函数*********************************  

142. // 1.人物贴图坐标修正及窗口贴图  

143. //进行AI行为判断并贴图  

144. void MyPaint(HDC hdc)  

145. {  

146.     int w,h,i;  

147.   

148.     //先在mdc中贴上背景图  

149.     SelectObject(bufdc,bg);  

150.     BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);  

151.   

152.     //按照目前的移动方向取出对应人物的连续走动图,并确定截取人物图的宽度与高度  

153.     SelectObject(bufdc,girl[dir]);  

154.     switch(dir)  

155.     {  

156.         case 0:  

157.             w = 55;  

158.             h = 74;  

159.             break;  

160.         case 1:  

161.             w = 53;  

162.             h = 77;  

163.             break;  

164.         case 2:  

165.             w = 60;  

166.             h = 74;  

167.             break;  

168.         case 3:  

169.             w = 60;  

170.             h = 74;  

171.             break;  

172.     }  

173.     //按照目前的XY的值在mdc上进行透明贴图,然后显示在窗口画面上  

174.     BitBlt(mdc,x,y,w,h,bufdc,num*w,h,SRCAND);  

175.     BitBlt(mdc,x,y,w,h,bufdc,num*w,0,SRCPAINT);  

176.       

177.   

178.   

179.   

180.     //贴出鸟的图片  

181.     SelectObject(bufdc,bird);  

182.   

183.   

184.     for(i=0;i<3;i++)  

185.     {  

186.   

187.         if(rand()%3 != 1)       //2/3几率进行追踪  

188.         {  

189.             if(p[i].y > y-16)  

190.                 p[i].y -= 5;  

191.             else  

192.                 p[i].y += 5;  

193.   

194.             if(p[i].x > x-25)  

195.                 p[i].x -= 5;  

196.             else  

197.                 p[i].x += 5;  

198.         }  

199.   

200.         if(p[i].x > x-25)    //判断小鸟的移动方向,从而选择合适的位图朝向  

201.         {  

202.             BitBlt(mdc,p[i].x,p[i].y,61,61,bufdc,61,61,SRCAND);  

203.             BitBlt(mdc,p[i].x,p[i].y,61,61,bufdc,0,61,SRCPAINT);  

204.         }  

205.         else  

206.         {  

207.             BitBlt(mdc,p[i].x,p[i].y,61,61,bufdc,61,0,SRCAND);  

208.             BitBlt(mdc,p[i].x,p[i].y,61,61,bufdc,0,0,SRCPAINT);  

209.         }  

210.     }  

211.   

212.     BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);  

213.   

214.   

215.   

216.   

217.     tPre = GetTickCount();         //记录此次绘图时间  

218.   

219.     num++;  

220.     if(num == 8)  

221.         num = 0;  

222.   

223. }  

224.   

225. //****消息处理函数***********************************  

226. // 1.按下【Esc】键结束程序  

227. // 2.按下方向键重设贴图坐标  

228. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  

229. {  

230.     switch (message)  

231.     {  

232.         case WM_KEYDOWN:         //按下键盘消息  

233.             //判断按键的虚拟键码  

234.             switch (wParam)   

235.             {  

236.                 case VK_ESCAPE:           //按下【Esc】键  

237.                     PostQuitMessage( 0 );  //结束程序  

238.                     break;  

239.                 case VK_UP:               //按下【】键  

240.                     //先按照目前的移动方向来进行贴图坐标修正,并加入人物往上移动的量(每次按下一次按键移动10个单位),来决定人物贴图坐标的XY值,接着判断坐标是否超出窗口区域,若有则再次修正  

241.                     switch(dir)  

242.                     {  

243.                         case 0:   

244.                             y -= 10;  

245.                             break;  

246.                         case 1:  

247.                             x -= 1;  

248.                             y -= 8;  

249.                             break;  

250.                         case 2:   

251.                             x += 2;  

252.                             y -= 10;  

253.                             break;  

254.                         case 3:  

255.                             x += 2;  

256.                             y -= 10;  

257.                             break;  

258.                     }  

259.                     if(y < 0)  

260.                         y = 0;  

261.                     dir = 0;  

262.                     break;  

263.                 case VK_DOWN:             //按下【】键  

264.                     switch(dir)  

265.                     {  

266.                         case 0:  

267.                             x += 1;  

268.                             y += 8;  

269.                             break;  

270.                         case 1:  

271.                             y += 10;  

272.                             break;  

273.                         case 2:  

274.                             x += 3;  

275.                             y += 6;  

276.                             break;  

277.                         case 3:  

278.                             x += 3;  

279.                             y += 6;  

280.                             break;  

281.                     }  

282.   

283.                     if(y > 375)  

284.                         y = 375;  

285.                     dir = 1;  

286.                     break;  

287.                 case VK_LEFT:             //按下【】键  

288.                     switch(dir)  

289.                     {  

290.                         case 0:  

291.                             x -= 12;  

292.                             break;  

293.                         case 1:  

294.                             x -= 13;  

295.                             y += 4;  

296.                             break;  

297.                         case 2:  

298.                             x -= 10;  

299.                             break;  

300.                         case 3:  

301.                             x -= 10;  

302.                             break;  

303.                     }  

304.                     if(x < 0)  

305.                         x = 0;  

306.                     dir = 2;  

307.                     break;  

308.                 case VK_RIGHT:             //按下【】键  

309.                     switch(dir)  

310.                     {  

311.                         case 0:  

312.                             x += 8;  

313.                             break;  

314.                         case 1:  

315.                             x += 7;  

316.                             y += 4;  

317.                             break;  

318.                         case 2:  

319.                             x += 10;  

320.                             break;  

321.                         case 3:  

322.                             x += 10;  

323.                             break;  

324.                     }  

325.                     if(x > 575)  

326.                         x = 575;  

327.                     dir = 3;  

328.                     break;  

329.             }  

330.             break;  

331.         case WM_DESTROY:                    //窗口结束消息  

332.             int i;  

333.   

334.             DeleteDC(mdc);  

335.             DeleteDC(bufdc);  

336.             for(i=0;i<4;i++)  

337.                 DeleteObject(girl[i]);  

338.             DeleteObject(bg);  

339.             ReleaseDC(hWnd,hdc);  

340.   

341.             PostQuitMessage(0);  

342.             break;  

343.         default:                            //其他消息  

344.             return DefWindowProc(hWnd, message, wParam, lParam);  

345.    }  

346.    return 0;  

347. }  







运行截图如下:

以及

运行这个小游戏,我们要用键盘的【】【】【】【】键来躲避小鸟的追击,小鸟则会不断向人物靠近。

之前小鸟闪烁的bug已经修复,感谢 lghui1 的指出,我是大意了,将背景图在hdc上绘制了两次。

已经下载源代码的朋友,请将177行的 BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);  删去即可。

本节笔记到这里就结束了,由于近期在做一个纯flash的网站,更新速度和评论的回复都不像往常那么及时,希望大家能够体谅。

作者:孙广东   邮箱: 1224708372@qq.com    欢迎邮件交流编程心得

由于百度文库不支持压缩文件格式,源代码不能分享,很抱歉,想要源代码的请把邮箱号码发给我。我会把源代码发给你。

我的百度空间文库:http://www.baidu.com/p/a1224708372?from=wenku欢迎访问,有更多专业资料。

本文来源:https://www.2haoxitong.net/k/doc/e2b1b48cec3a87c24028c4c3.html

《VC++2010游戏开发随记之十五.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式