1、VC+游戏开发随记之二十二【Visual C+】游戏开发笔记二十二 游戏基础物理建模(四) 粒子系统模拟(一)本节内容主要讲解了在GDI中粒子的运用,为后续DirectX中粒子系统的讲解提供一个初步的认识。一基础知识讲解1.基本概念粒子是一种微小的物体,在数学上通常用点来表示其模型。我们可以把粒子想象成颗粒状的物体,如雪花,雨滴,沙尘,烟雾等特殊的事物。又比如游戏中的怪物,晶体,材料,在需要的时候,也可以通过粒子来实现。俗话说“不积跬步,无以至千里,不积小流,何以成江海”,单个的粒子是比较平凡的存在,但是如果将大量的粒子聚到一起,就可以实现很多神奇的效果了。在C/C+中想要定义一个粒子是非常容
2、易的。基本功扎实的朋友们肯定马上就可以想到,“结构体“是用来定义粒子类型的绝佳武器。原则上用“类”也可以实现,但是在这里采用“结构体”将更加合适。2.实现方法如下面的这个结构体snow便是用来定义“雪花”粒子的:cppview plaincopyprint?1. structsnow2. 3. intx;/雪花的X坐标4. inty;/雪花的Y坐标5. BOOLexist;/雪花是否存在6. ;可以看出,上述结构体中有3个成员,分别是代表X坐标的x,代表Y坐标的y,与表示雪花是否存在的布尔型变量exist。定义完粒子的结构体后,便可以实例化一个粒子数组了。如果我们需要一个大小为50的snowf
3、ly数组,则可用一下两种方法来进行:在结构体的尾部加上我们需要实例化的对象cppview plaincopyprint?1. structsnow2. 3. intx;/雪花的X坐标4. inty;/雪花的Y坐标5. BOOLexist;/雪花是否存在6. snowfly50;单独定义cppview plaincopyprint?1. snowsnowfly50;定义完之后,就可以在这个粒子数组的基础上,用代码进行相关功能的实现了。以上就是粒子系统概念的一个简明扼要的讲解。而下面我们依旧是通过一个实例来巩固本节所学。二、详细注释的源代码欣赏在贴出全部的源代码之前,我们先把最关键的部分提出来先剖
4、析一下,下面是本节实例的核心代码:cppview plaincopyprint?1. /全局变量声明2. HINSTANCEhInst;3. HBITMAPbg,snow,mask;/用于贴图的三个HBITMAP变量4. HDChdc,mdc,bufdc;5. HWNDhWnd;6. RECTrect;7. inti,count;/定义count用于计数8. 9. /*自定义绘图函数*10. /1.窗口贴图11. /2.实现雪花纷飞的效果12. voidMyPaint(HDChdc)13. 14. 15. /创建粒子16. if(count50)/当粒子数小于50时,产生新的粒子,设定每个粒子
5、的属性值17. 18. dropcount.x=rand()%rect.right;/将粒子的X坐标设为窗口中水平方向上的任意位置19. dropcount.y=0;/将每个粒子的Y坐标都设为0,即从窗口上沿往下落20. dropcount.exist=true;/设定粒子存在21. count+;/每产生一个粒子后进行累加计数22. 23. 24. 25. /贴上背景图到mdc中26. SelectObject(bufdc,bg);27. BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);28. 29. /首先判断粒子是否存在,若存在,进行透明贴图操作30.
6、 for(i=0;irect.bottom)47. 48. dropi.x=rand()%rect.right;49. dropi.y=0;50. 51. 52. 53. 54. 55. 56. /将mdc中的全部内容贴到hdc中57. BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);58. 59. MyPaint函数的书写思路是,先初始化每个粒子,这里是共50个粒子。然后贴上背景图到mdc中,再用循环将各个粒子也贴到mdc中,循环完成之后,再统一将mdc中的内容直接贴到hdc中。这样做的优点是比较直观,提高了贴图的效率。下面就贴出全部详细注释的源代码,供大家学
7、习,需要在自己机器上运行并学习提高的朋友,请点击文章末尾处贴出的地址进行下载。源代码依旧是分为VC6.0和VS2010两个版本。这里贴出的是VC6.0版的:cppview plaincopyprint?1. #includestdafx.h2. #include3. 4. /全局变量声明5. HINSTANCEhInst;6. HBITMAPbg,snow,mask;/用于贴图的三个HBITMAP变量7. HDChdc,mdc,bufdc;8. HWNDhWnd;9. RECTrect;10. inti,count;/定义count用于计数11. 12. 13. 14. 15. structs
8、now16. 17. intx;18. inty;19. BOOLexist;20. drop50;21. 22. 23. /全局函数声明 24. ATOMMyRegisterClass(HINSTANCEhInstance);25. BOOLInitInstance(HINSTANCE,int);26. LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);27. voidMyPaint(HDChdc);28. 29. /*WinMain函数,程序入口点函数*30. intAPIENTRYWinMain(HINSTANCEhInstance,31.
9、HINSTANCEhPrevInstance,32. LPSTRlpCmdLine,33. intnCmdShow)34. 35. MSGmsg;36. 37. MyRegisterClass(hInstance);38. 39. /初始化40. if(!InitInstance(hInstance,nCmdShow)41. 42. returnFALSE;43. 44. 45. 46. /消息循环47. while(GetMessage(&msg,NULL,0,0)48. 49. TranslateMessage(&msg);50. DispatchMessage(&msg);51. 52.
10、 53. returnmsg.wParam;54. 55. 56. /*设计一个窗口类,类似填空题,使用窗口结构体*57. ATOMMyRegisterClass(HINSTANCEhInstance)58. 59. WNDCLASSEXwcex;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
11、=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=maple;73. wcex.hIconSm=NULL;74. 75. returnRegisterClassEx(&wcex);76. 77. 78. /*初始化函数*79. /1.加载位图资源80. /2.
12、取得内部窗口区域信息81. BOOLInitInstance(HINSTANCEhInstance,intnCmdShow)82. 83. HBITMAPbmp;84. hInst=hInstance;85. 86. hWnd=CreateWindow(maple,浅墨的绘图窗口,WS_OVERLAPPEDWINDOW,87. CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);88. 89. if(!hWnd)90. 91. returnFALSE;92. 93. 94. MoveWindow(hWnd,10,10,600,45
13、0,true);95. ShowWindow(hWnd,nCmdShow);96. UpdateWindow(hWnd);97. 98. hdc=GetDC(hWnd);99. mdc=CreateCompatibleDC(hdc);100. 101. bufdc=CreateCompatibleDC(hdc);102. bmp=CreateCompatibleBitmap(hdc,640,480);103. 104. SelectObject(mdc,bmp);105. 106. 107. 108. 109. bg=(HBITMAP)LoadImage(NULL,bg.bmp,IMAGE_B
14、ITMAP,rect.right,rect.bottom,LR_LOADFROMFILE);110. snow=(HBITMAP)LoadImage(NULL,snow.bmp,IMAGE_BITMAP,20,20,LR_LOADFROMFILE);111. mask=(HBITMAP)LoadImage(NULL,mask.bmp,IMAGE_BITMAP,20,20,LR_LOADFROMFILE);112. GetClientRect(hWnd,&rect);113. 114. 115. 116. SetTimer(hWnd,1,0,NULL);117. 118. MyPaint(hdc
15、);119. 120. returnTRUE;121. 122. 123. /*自定义绘图函数*124. /1.窗口贴图125. /2.实现雪花纷飞的效果126. voidMyPaint(HDChdc)127. 128. 129. /创建粒子130. if(count50)/当粒子数小于50时,产生新的粒子,设定每个粒子的属性值131. 132. dropcount.x=rand()%rect.right;/将粒子的X坐标设为窗口中水平方向上的任意位置133. dropcount.y=0;/将每个粒子的Y坐标都设为0,即从窗口上沿往下落134. dropcount.exist=true;/设定
16、粒子存在135. count+;/每产生一个粒子后进行累加计数136. 137. 138. 139. /贴上背景图到mdc中140. SelectObject(bufdc,bg);141. BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);142. 143. /首先判断粒子是否存在,若存在,进行透明贴图操作144. for(i=0;irect.bottom)161. 162. dropi.x=rand()%rect.right;163. dropi.y=0;164. 165. 166. 167. 168. 169. 170. /将mdc中的全部内容贴到hdc中
17、171. BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);172. 173. 174. 175. 176. 177. /*消息处理函数*178. LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)179. 180. switch(message)181. 182. caseWM_TIMER:/时间消息183. MyPaint(hdc);/在消息循环中加入处理WM_TIMER消息,当接收到此消息时便调用MyPaint()函数进行窗口绘图184. break;185. case
18、WM_KEYDOWN:/按键消息186. if(wParam=VK_ESCAPE)/按下【Esc】键187. PostQuitMessage(0);188. break;189. caseWM_DESTROY:/窗口结束消息190. DeleteDC(mdc);191. DeleteDC(bufdc);192. DeleteObject(bg);193. DeleteObject(snow);194. DeleteObject(mask);195. KillTimer(hWnd,1);/窗口结束时,删除所建立的定时器196. ReleaseDC(hWnd,hdc);197. PostQuitM
19、essage(0);198. break;199. default:/其他消息200. returnDefWindowProc(hWnd,message,wParam,lParam);201. 202. return0;203. 下面是运行后的截图效果:可以看到窗口中有漫天飞舞的雪花,我们可以调节数组大小,及几处设定的数值的大小,来使雪花来得更猛烈些。这张背景图是否有些熟悉呢?哈哈,喜欢打Dota的朋友们应该可以发现,这张图就是Dota的游戏原画(或者说是魔兽争霸冰封王座的原画,因为Dota其实就是基于这款游戏的一张自定义多人对战地图罢了),左边的显然就是恐怖利刃TerroBlade(咦,他的双刀呢?),中间远远在背后摆造型的是召唤师卡尔,而最右边的当然就是目前Dota中的“一姐”蛇发女妖美杜莎了。在文章末尾说点题外话吧。关于大家提到的总是熬夜的问题,其实浅墨从来都不熬夜的- -。因为浅墨目前是在欧洲,经常是在当地时间晚上10点左右把最新的文章发表出来,所以大家在中国看到的都是半夜3点4点左右发表的文章,所以不要以为浅墨是熬夜码字啦,那是因为时差问题 -o-好了,本篇就写到这里吧,谢谢大家的观赏,下面依旧是放出两个版本的源代码供大家下载学习)(当然,必须是零资
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2