11. {
12. if(pop[j+1].y < pop[j].y)
13. { //进行数组元素的交换
14. tmp = pop[j+1];
15. pop[j+1] = pop[j];
16. pop[j] = tmp;
17. f = true;
18. }
19. }
20. if(!
f) //无交换操作则结束循环
21. break;
22. }
23.}
各种排序法为C/C++中比较核心的知识点,还不太熟悉的朋友,可以参看各种C++,数据结构的教程进行深入学习。
在这里我就不多做介绍了。
接下来,我们来利用一个范例来演示气泡排序法在画面上贴图的运用,让动画能呈现出接近真实的远近层次效果。
这个范例比较有趣,会产生多只恐龙随机跑动,每次进行画面贴图前先完成排序操作,并对恐龙跑动进行贴图坐标的修正,呈现出比较顺畅真实的动画来。
废话这里就不多说了,直接上已经详细注释的代码(这回的代码量就有些大了,不过我专门注释得更详细了些,其实它比之前的代码还更好懂):
[cpp] viewplaincopyprint?
1.#include "stdafx.h"
2.#include
3.
4.//定义一个结构体
5.struct dragon //定义dragon结构,代表画面上的恐龙,其结构成员x和y为贴图坐标,dir为目前恐龙的移动方向
6.{
7. int x,y;
8. int dir;
9.};
10.
11.//定义常数
12.const int draNum = 12; //定义常数draNum,代表程序在画面上要出现的恐龙数目,在此设定为12个
13.//全局变量定义
14.HINSTANCE hInst;
15.HBITMAP draPic[4],bg; //draPic[4]储存恐龙上下左右移动的连续图案,bg为存储背景图
16.HDC hdc,mdc,bufdc;
17.HWND hWnd;
18.DWORD tPre,tNow;
19.int picNum;
20.dragon dra[draNum]; //按照draNum的值建立数组dra[],产生画面上出现的恐龙。
21.
22.
23.//全局函数声明
24.ATOM MyRegisterClass(HINSTANCE hInstance);
25.BOOL InitInstance(HINSTANCE, int);
26.LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
27.void MyPaint(HDC hdc);
28.
29.//****WinMain函数,程序入口点函数**************************************
30.int APIENTRY WinMain(HINSTANCE hInstance,
31. HINSTANCE hPrevInstance,
32. LPSTR lpCmdLine,
33. int nCmdShow)
34.{
35. MSG msg;
36.
37. MyRegisterClass(hInstance);
38.
39. //初始化
40. if (!
InitInstance (hInstance, nCmdShow))
41. {
42. return FALSE;
43. }
44. GetMessage(&msg,NULL,NULL,NULL);//初始化msg
45. //消息循环
46. while( msg.message!
=WM_QUIT )
47. {
48. if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
49. {
50. TranslateMessage( &msg );
51. DispatchMessage( &msg );
52. }
53. else
54. {
55. tNow = GetTickCount();
56. if(tNow-tPre >= 100)
57. MyPaint(hdc);
58. }
59. }
60.
61. return msg.wParam;
62.}
63.
64.//****设计一个窗口类,类似填空题,使用窗口结构体*************************
65.ATOM MyRegisterClass(HINSTANCE hInstance)
66.{
67. WNDCLASSEX wcex;
68.
69. wcex.cbSize = sizeof(WNDCLASSEX);
70. wcex.style = CS_HREDRAW | CS_VREDRAW;
71. wcex.lpfnWndProc = (WNDPROC)WndProc;
72. wcex.cbClsExtra = 0;
73. wcex.cbWndExtra = 0;
74. wcex.hInstance = hInstance;
75. wcex.hIcon = NULL;
76. wcex.hCursor = NULL;
77. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
78. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
79. wcex.lpszMenuName = NULL;
80. wcex.lpszClassName = "canvas";
81. wcex.hIconSm = NULL;
82.
83. return RegisterClassEx(&wcex);
84.}
85.
86.//****初始化函数*************************************
87.// 加载位图并设定各初始值
88.BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
89.{
90. HBITMAP bmp;
91. hInst = hInstance;
92. int i;
93.
94. hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,
95. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
96.
97. if (!
hWnd)
98. {
99. return FALSE;
100. }
101.
102. MoveWindow(hWnd,10,10,640,480,true);
103. ShowWindow(hWnd, nCmdShow);
104. UpdateWindow(hWnd);
105.
106. hdc = GetDC(hWnd);
107. mdc = CreateCompatibleDC(hdc);
108. bufdc = CreateCompatibleDC(hdc);
109.
110. bmp = CreateCompatibleBitmap(hdc,640,480); //建立一个空位图并放入mdc中
111. SelectObject(mdc,bmp);
112.
113.
114. //加载各张恐龙跑动图及背景图,这里以0,1,2,3来代表恐龙的上,下,左,右移动
115. draPic[0] = (HBITMAP)LoadImage(NULL,"dra0.bmp",IMAGE_BITMAP,528,188,LR_LOADFROMFILE);
116. draPic[1] = (HBITMAP)LoadImage(NULL,"dra1.bmp",IMAGE_BITMAP,544,164,LR_LOADFROMFILE);
117. draPic[2] = (HBITMAP)LoadImage(NULL,"dra2.bmp",IMAGE_BITMAP,760,198,LR_LOADFROMFILE);
118. draPic[3] = (HBITMAP)LoadImage(NULL,"dra3.bmp",IMAGE_BITMAP,760,198,LR_LOADFROMFILE);
119. bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,640,480,LR_LOADFROMFILE);
120.
121.
122. //设定所有恐龙初始的贴图坐标都为(200,200),初始的移动方向都为向左。
123. for(i=0;i124. {
125. dra[i].dir = 3; //起始方向
126. dra[i].x = 200; //贴图的起始X坐标
127. dra[i].y = 200; //贴图的起始Y坐标
128. }
129.
130. MyPaint(hdc);
131.
132. return TRUE;
133.}
134.
135.//气泡排序
136.void BubSort(int n)
137.{
138. int i,j;
139. bool f;
140. dragon tmp;
141.
142. for(i=0;i143. {
144. f = false;
145. for(j=0;j146. {
147. if(dra[j+1].y < dra[j].y)
148. {
149. tmp = dra[j+1];
150. dra[j+1] = dra[j];
151. dra[j] = tmp;
152. f = true;
153. }
154. }
155. if(!
f)
156. break;
157. }
158.}
159.
160.//****自定义绘图函数*********************************
161.// 1.对窗口中跑动的恐龙进行排序贴图
162.// 2.恐龙贴图坐标修正
163.void MyPaint(HDC hdc)
164.{
165. int w,h,i;
166.
167. if(picNum == 8)
168. picNum = 0;
169.
170. //在mdc中先贴上背景图
171. SelectObject(bufdc,bg);
172. BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);
173.
174. BubSort(draNum); //贴上恐龙图之前调用BubSort()函数进行排序
175.
176.
177. //下面这个for循环,按照目前恐龙的移动方向dra[i].dir,选取对应的位图到bufdc中,并设定截切的大小。
每一张要在窗口上出现的恐龙图案依次先在mdc上进行透明贴图的操作。
178. for(i=0;i179. {
180. SelectObject(bufdc,draPic[dra[i].dir]);
181. switch(dra[i].dir)
182. {
183. case 0:
184. w = 66;
185. h = 94;
186. break;
187. case 1:
188. w = 68;
189. h = 82;
190. break;
191. case 2:
192. w = 95;
193. h = 99;
194. break;
195. case 3:
196. w = 95;
197. h = 99;
198. break;
199. }
200. BitBlt(mdc,dra[i].x,dra[i].y,w,h,bufdc,picNum*w,h,SRCAND);
201. BitBlt(mdc,dra[i].x,dra[i].y,w,h,bufdc,picNum*w,0,SRCPAINT);
202. }
203.
204. //将最后画面显示在窗口中
205. BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);
206.
207. tPre = GetTickCount(); //记录此次绘图时间
208. picNum++;
209.
210.
211. //下面这个for循环,决定每一只恐龙下一次的移动方向及贴图坐标
212. for(i=0;i213. {
214. switch(rand()%4) //随机数除以4的余数来决定下次移动方向,余数0,1,2,3分别代表上,下,左,右
215. {
216. //case 0里面的代码,按照目前的移动方向来修正因为各个方向图案尺寸不一致而产生的贴图坐标误差,加入恐龙每次移动的单位量(上,下,左,右每次20个单位)而得到下次新的贴图坐标
217. case 0:
//上
218. switch(dra[i].dir)
219. {
220. case 0:
221. dra[i].y -= 20;
222. break;
223. case 1:
224. dra[i].x += 2;
225. dra[i].y -= 31;
226. break;
227. case 2:
228. dra[i].x += 14;
229. dra[i].y -= 20;
230. break;
231. case 3:
232. dra[i].x += 14;
233. dra[i].y -= 20;
234. break;
235. }
236. //在计算出新的贴图坐标之后,还需判断此新的坐标会不会使得恐龙贴图超出窗口边界,若超出,则将该方向上的坐标设定为刚好等于临界值
237. if(dra[i].y < 0)
238. dra[i].y = 0;
239. dra[i].dir = 0;
240. break;
241. //其他方向按照和上面相同的方法计算
242. case 1:
//下
243. switch(dra[i].dir)
244. {
245. case 0:
246. dra[i].x -= 2;
247. dra[i].y += 31;
248. break;
249.