Visual C++游戏开发笔记二十三 游戏基础物理建模五 粒子系统模拟二.docx
《Visual C++游戏开发笔记二十三 游戏基础物理建模五 粒子系统模拟二.docx》由会员分享,可在线阅读,更多相关《Visual C++游戏开发笔记二十三 游戏基础物理建模五 粒子系统模拟二.docx(23页珍藏版)》请在冰豆网上搜索。
VisualC++游戏开发笔记二十三游戏基础物理建模五粒子系统模拟二
【VisualC++】游戏开发笔记二十三游戏基础物理建模(五)粒子系统模拟
(二)
本系列文章由zhmxy555(毛星云)编写,转载请注明出处。
作者:
毛星云 邮箱:
happylifemxy@ 期待着与志同道合的朋友们相互交流
本节在笔记二十二的基础上继续讲解了例子系统的模拟与实际运用,着重讲解和分析了基于例子系统的一个“星光绽放
demo”,最后盘点了史诗级游戏作品《暗黑破坏神3》上市首周所创下的传奇。
一.基础知识讲解
1. 概念与思路
基本的粒子系统概念在笔记二十二中已经讲过了,还不太清楚的朋友请移步前篇:
【VisualC++】游戏开发笔记二十二游戏基础物理建模(四)粒子系统模拟
(一)
本节讲解的星光绽放demo相当于是一个模拟爆炸(或者说是烟花)特效的demo,浅墨认为这个特效拿出来讲解很多必要性,它可以为很多问题带来的思路的火花。
这个demo之中,绽放(爆炸)点为在窗口中由随机数产生的一个位置,绽放(爆炸)后,会出现很多星光以不同的速度向四方飞散而去,当粒子飞出窗口后或者超出时间后便会消失。
每一次爆炸所出现的粒子全部消失后,便会重新出现绽放(爆炸)的画面,以产生不断绽放星光的效果。
2.“星光”粒子的构造
首先我们来看一下这次如何用结构体来构造出星光粒子:
[cpp] viewplaincopyprint?
1.struct flystar
2.{
3. int x; //星光所在的x坐标
4. int y; //星光所在的y坐标
5. int vx; //星光x方向的速度
6. int vy; //星光y方向的速度
7. int lasted; //星光存在的时间
8. BOOL exist; //星光是否存在
9.}flystar[50];
6个成员分别为,粒子坐标两个值,粒子方向两个值,持续时间lasted,和粒子是否存在的标识exist。
3.核心代码讲解
最重要的当然是我们的MyPaint()绘图函数:
[cpp] viewplaincopyprint?
1.//全局变量声明
2.HINSTANCE hInst;
3.HBITMAP bg,star,mask; //用于贴图的三个HBITMAP变量
4.HDC hdc,mdc,bufdc;
5.HWND hWnd;
6.RECT rect;
7.int i,count; //定义count用于计数
8.
9.
10.//****自定义绘图函数*********************************
11.// 1.窗口贴图
12.// 2.实现星光绽放的效果
13.void MyPaint(HDC hdc)
14.{
15.
16.
17.
18.
19.//创建粒子
20. if(count == 0) //随机设置爆炸点
21. {
22. int x=rand()%rect.right;
23. int y=rand()%rect.bottom;
24. for(i=0;i<50;i++) //产生星光粒子
25. {
26. flystar[i].x = x;
27. flystar[i].y = y;
28. flystar[i].lasted = 0; //设定该粒子存在的时间为零
29. if(i%2==0) //按粒子编号i来决定粒子在哪个象限运动,且x,y方向的移动速度随机为1—15之间的一个值,由1+rand()%15来完成。
30. {
31. flystar[i].vx = -(1+rand()%15);
32. flystar[i].vy = -(1+rand()%15);
33. }
34. if(i%2==1)
35. {
36. flystar[i].vx = 1+rand()%15;
37. flystar[i].vy = 1+rand()%15;
38. }
39. if(i%4==2)
40. {
41. flystar[i].vx = -(1+rand()%15);
42. flystar[i].vy = 1+rand()%15;
43. }
44. if(i%4==3)
45. {
46. flystar[i].vx = 1+rand()%15;
47. flystar[i].vy = -(1+rand()%15);
48. }
49. flystar[i].exist = true; //设定粒子存在
50. }
51. count = 50; //50个粒子由for循环设置完成后,我们将粒子数量设为50,代表目前有50颗星光
52. }
53.
54. //先在内存dc中贴上背景图片
55. SelectObject(bufdc,bg);
56. BitBlt(mdc,0,0,rect.right,rect.bottom,bufdc,0,0,SRCCOPY);
57.
58.
59. for(i=0;i<50;i++)
60. {
61. if(flystar[i].exist) //判断粒子是否还存在,若存在,则根据其坐标(flystar[i].x,flystar[i].y)进行贴图操作
62. {
63. SelectObject(bufdc,mask);
64. BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,0,0,SRCAND);
65. SelectObject(bufdc,star);
66. BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,0,0,SRCPAINT);
67.
68.
69. //计算下一次贴图的坐标
70. flystar[i].x+=flystar[i].vx;
71. flystar[i].y+=flystar[i].vy;
72.
73.
74. //在每进行一次贴图后,将粒子的存在时间累加1.
75. flystar[i].lasted++;
76. //进行条件判断,若某粒子跑出窗口区域一定的范围,则将该粒子设为不存在,且粒子数随之递减
77. if(flystar[i].x<=-10 || flystar[i].x>rect.right || flystar[i].y<=-10 || flystar[i].y>rect.bottom || flystar[i].lasted>50)
78. {
79. flystar[i].exist = false; //删除星光粒子
80. count--; //递减星光总数
81. }
82. }
83. }
84.
85.//将mdc中的全部内容贴到hdc中
86. BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);
87.
88.
89.}
相关的书写思路在代码注释中浅墨已经写得比较清晰了。
这段代码的书写整体思路即:
第一步,判断粒子是否创建,若星光数量count不为0,则直接跳到第四步进行相关贴图操作。
否则需按每步顺序完成粒子的初始化。
第二步,随机设置绽放点。
第三步,创建各个粒子(为结构体各属性赋值)。
第四步,在内存dc上贴上背景图片。
第五步,对各个粒子进行贴图操作并
第六步,对某些值,如count,exist进行特殊的处理
第七步,将mdc(内存dc)中的内容贴到hdc中,完成最后在屏幕上的显示。
二、详细注释的源代码欣赏
OK,讲解完成,现在我们就贴出详细注释的源代码:
[cpp] viewplaincopyprint?
1.#include "stdafx.h"
2.#include
3.
4.//全局变量声明
5.HINSTANCE hInst;
6.HBITMAP bg,star,mask; //用于贴图的三个HBITMAP变量
7.HDC hdc,mdc,bufdc;
8.HWND hWnd;
9.RECT rect;
10.int i,count; //定义count用于计数
11.
12.
13.
14.
15.struct flystar
16.{
17. int x; //星光所在的x坐标
18. int y; //星光所在的y坐标
19. int vx; //星光x方向的速度
20. int vy; //星光y方向的速度
21. int lasted; //星光存在的时间
22. BOOL exist; //星光是否存在
23.}flystar[50];
24.
25.
26.//全局函数声明
27.ATOM MyRegisterClass(HINSTANCE hInstance);
28.BOOL InitInstance(HINSTANCE, int);
29.LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
30.void MyPaint(HDC hdc);
31.
32.//****WinMain函数,程序入口点函数**************************************
33.int APIENTRY WinMain(HINSTANCE hInstance,
34. HINSTANCE hPrevInstance,
35. LPSTR lpCmdLine,
36. int nCmdShow)
37.{
38. MSG msg;
39.
40. MyRegisterClass(hInstance);
41.
42. //初始化
43. if (!
InitInstance (hInstance, nCmdShow))
44. {
45. return FALSE;
46. }
47.
48.
49. //消息循环
50. while (GetMessage(&msg, NULL, 0, 0))
51. {
52. TranslateMessage(&msg);
53. DispatchMessage(&msg);
54. }
55.
56. return msg.wParam;
57.}
58.
59.//****设计一个窗口类,类似填空题,使用窗口结构体*********************
60.ATOM MyRegisterClass(HINSTANCE hInstance)
61.{
62. WNDCLASSEX wcex;
63.
64. wcex.cbSize = sizeof(WNDCLASSEX);
65. wcex.style = CS_HREDRAW | CS_VREDRAW;
66. wcex.lpfnWndProc = (WNDPROC)WndProc;
67. wcex.cbClsExtra = 0;
68. wcex.cbWndExtra = 0;
69. wcex.hInstance = hInstance;
70. wcex.hIcon = NULL;
71. wcex.hCursor = NULL;
72. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
73. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
74. wcex.lpszMenuName = NULL;
75. wcex.lpszClassName = "maple";
76. wcex.hIconSm = NULL;
77.
78. return RegisterClassEx(&wcex);
79.}
80.
81.//****初始化函数*************************************
82.// 1.加载位图资源
83.// 2.取得内部窗口区域信息
84.BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
85.{
86. HBITMAP bmp;
87. hInst = hInstance;
88.
89. hWnd = CreateWindow("maple", "浅墨的绘图窗口" , WS_OVERLAPPEDWINDOW,
90. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
91.
92. if (!
hWnd)
93. {
94. return FALSE;
95. }
96.
97. MoveWindow(hWnd,10,10,600,450,true);
98. ShowWindow(hWnd, nCmdShow);
99. UpdateWindow(hWnd);
100.
101. hdc = GetDC(hWnd);
102. mdc = CreateCompatibleDC(hdc);
103.
104. bufdc = CreateCompatibleDC(hdc);
105. bmp = CreateCompatibleBitmap(hdc,640,480);
106.
107. SelectObject(mdc,bmp);
108.
109.
110.
111.
112. bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,rect.right,rect.bottom,LR_LOADFROMFILE);
113. star = (HBITMAP)LoadImage(NULL,"star.bmp",IMAGE_BITMAP,30,30,LR_LOADFROMFILE);
114. mask = (HBITMAP)LoadImage(NULL,"mask.bmp",IMAGE_BITMAP,30,30,LR_LOADFROMFILE);
115. GetClientRect(hWnd,&rect);
116.
117.
118.
119. SetTimer(hWnd,1,0,NULL);
120.
121. MyPaint(hdc);
122.
123. return TRUE;
124.}
125.
126.//****自定义绘图函数*********************************
127.// 1.窗口贴图
128.// 2.实现星光绽放的效果
129.void MyPaint(HDC hdc)
130.{
131.
132.
133.//创建粒子
134. if(count == 0) //随机设置爆炸点
135. {
136. int x=rand()%rect.right;
137. int y=rand()%rect.bottom;
138. for(i=0;i<50;i++) //产生星光粒子
139. {
140. flystar[i].x = x;
141. flystar[i].y = y;
142. flystar[i].lasted = 0; //设定该粒子存在的时间为零
143. if(i%2==0) //按粒子编号i来决定粒子在哪个象限运动,且x,y方向的移动速度随机为1—15之间的一个值,由1+rand()%15来完成。
144. {
145. flystar[i].vx = -(1+rand()%15);
146. flystar[i].vy = -(1+rand()%15);
147. }
148. if(i%2==1)
149. {
150. flystar[i].vx = 1+rand()%15;
151. flystar[i].vy = 1+rand()%15;
152. }
153. if(i%4==2)
154. {
155. flystar[i].vx = -(1+rand()%15);
156. flystar[i].vy = 1+rand()%15;
157. }
158. if(i%4==3)
159. {
160. flystar[i].vx = 1+rand()%15;
161. flystar[i].vy = -(1+rand()%15);
162. }
163. flystar[i].exist = true; //设定粒子存在
164. }
165. count = 50; //50个粒子由for循环设置完成后,我们将粒子数量设为50,代表目前有50颗星光
166. }
167.
168. //先在内存dc中贴上背景图片
169. SelectObject(bufdc,bg);
170. BitBlt(mdc,0,0,rect.right,rect.bottom,bufdc,0,0,SRCCOPY);
171.
172. for(i=0;i<50;i++)
173. {
174. if(flystar[i].exist) //判断粒子是否还存在,若存在,则根据其坐标(flystar[i].x,flystar[i].y)进行贴图操作
175. {
176. SelectObject(bufdc,mask);
177. BitBlt(mdc,flystar[i].x,flystar[i].y,30,30,bufdc,