1 #include <windows.h>
2 #include <tchar.h> //swprintf_s函数所需的头文件
3 #include <time.h>
4
5 #pragma comment(lib, "winmm.lib") //playSound
6 #pragma comment(lib, "Msimg32.lib") //TransparentBlt
7
8 #define WINDOW_WIDTH 950
9 #define WINDOW_HEIGHT 710
10 #define WINDOW_TITLE L"Windows粒子系统"
11 // 表示粒子数量
12 #define FLYSTAR_NUMBER 100
13 // 表示粒子持续帧数,修改每次星光绽放持续的时间
14 #define FLYSTAR_LASTED_FRAME 60
15
16
17 struct FLYSTAR
18 {
19 int x; //星光所在的x坐标
20 int y; //星光所在的y坐标
21 int vx; //星光x方向的速度
22 int vy; //星光y方向的速度
23 int lasted; //星光存在的时间
24 BOOL exist; //星光是否存在
25 };
26 // 环境,内存句柄
27 HDC g_hdc = NULL, g_mdc = NULL, g_bufdc = NULL;
28 HBITMAP g_hStar = NULL, g_hBackGround = NULL;
29 DWORD g_tPre = 0, g_tNow = 0;
30 // 储存内部窗口区域的坐标
31 RECT g_rect;
32 FLYSTAR FlyStars[FLYSTAR_NUMBER];
33 int g_StarNum = 0;
34
35 // 回调函数,窗口过程函数
36 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
37 BOOL Game_Init(HWND hwnd);
38 VOID Game_Paint(HWND hwnd);
39 BOOL Game_CleanUp(HWND hwnd);
40
41
42 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
43 {
44 WNDCLASSEX wndClass = { 0 };
45 wndClass.cbSize = sizeof(WNDCLASSEX);
46 wndClass.style = CS_HREDRAW | CS_VREDRAW;
47 wndClass.lpfnWndProc = WndProc;
48 wndClass.cbClsExtra = 0;
49 wndClass.cbWndExtra = 0;
50 wndClass.hInstance = hInstance;
51 wndClass.hIcon = 0;
52 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
53 // 白色画刷句柄
54 wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
55 // 用一个以空终止的字符串,指定菜单资源的名字
56 wndClass.lpszMenuName = NULL;
57 //窗口类的名字
58 wndClass.lpszClassName = L"Game Develop";
59
60 if (!RegisterClassEx(&wndClass))
61 return -1;
62
63 // 正式创建窗口
64 HWND hwnd = CreateWindow(L"Game Develop", WINDOW_TITLE,
65 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
66 WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
67
68 MoveWindow(hwnd, 150, 50, WINDOW_WIDTH, WINDOW_HEIGHT, true);
69 ShowWindow(hwnd, nShowCmd);
70 UpdateWindow(hwnd);
71
72 if (!Game_Init(hwnd))
73 {
74 MessageBox(hwnd, L"资源初始化失败", L"消息窗口", 0);
75 return FALSE;
76 }
77
78 PlaySound(L"music.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
79
80 MSG msg = { 0 };
81 while (msg.message != WM_QUIT)
82 {
83 // 查看应用程序消息队列,有消息时将队列中的消息派发出去
84 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
85 {
86 TranslateMessage(&msg);
87 DispatchMessage(&msg);
88 }
89 else
90 {
91 g_tNow = GetTickCount();
92 // 重绘
93 if (g_tNow - g_tPre >= 40)
94 Game_Paint(hwnd);
95 }
96 }
97
98 // 程序准备结束,注销窗口类
99 UnregisterClass(L"Game Develop", wndClass.hInstance);
100 return 0;
101 }
102
103 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
104 {
105 switch (message)
106 {
107 case WM_KEYDOWN:
108 if (wParam == VK_ESCAPE)
109 PostQuitMessage(0);
110 break;
111
112 case WM_DESTROY:
113 Game_CleanUp(hwnd);
114 PostQuitMessage(0);
115 break;
116
117 //调用缺省的窗口过程
118 default:
119 return DefWindowProc(hwnd, message, wParam, lParam);
120 }
121 return 0;
122 }
123
124 BOOL Game_Init(HWND hwnd)
125 {
126 // 用系统时间初始化
127 // 随机数发生器的初始化函数
128 srand((unsigned)time(NULL));
129
130 HBITMAP bmp;
131 g_hdc = GetDC(hwnd);
132 g_mdc = CreateCompatibleDC(g_hdc);
133 g_bufdc = CreateCompatibleDC(g_hdc);
134 bmp = CreateCompatibleBitmap(g_hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
135
136 SelectObject(g_mdc, bmp);
137 g_hBackGround = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
138 g_hStar = (HBITMAP)LoadImage(NULL, L"star.bmp", IMAGE_BITMAP, 30, 30, LR_LOADFROMFILE);
139
140 // 取得内部窗口大小
141 GetClientRect(hwnd, &g_rect);
142
143 Game_Paint(hwnd);
144 return TRUE;
145 }
146
147 VOID Game_Paint(HWND hwnd)
148 {
149 // 先在mdc中贴上背景图
150 SelectObject(g_bufdc, g_hBackGround);
151 // 将源矩形区域直接拷贝到目标矩形区域
152 BitBlt(g_mdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);
153
154 // 创建粒子
155 if (g_StarNum == 0)
156 {
157 // 随机设置爆炸点
158 int x = rand() % g_rect.right;
159 int y = rand() % g_rect.bottom;
160
161 for (int i = 0; i < FLYSTAR_NUMBER; i++)
162 {
163 FlyStars[i].x = x;
164 FlyStars[i].y = y;
165 FlyStars[i].lasted = 0;
166 // x,y方向的移动速度随机为1—15之间的一个值
167 if (i % 4 == 0)
168 {
169 FlyStars[i].vx = -(1 + rand() % 15);
170 FlyStars[i].vy = -(1 + rand() % 15);
171 }
172 if (i % 4 == 1)
173 {
174 FlyStars[i].vx = (1 + rand() % 15);
175 FlyStars[i].vy = (1 + rand() % 15);
176 }
177 if (i % 4 == 2)
178 {
179 FlyStars[i].vx = -(1 + rand() % 15);
180 FlyStars[i].vy = (1 + rand() % 15);
181 }
182 if (i % 4 == 3)
183 {
184 FlyStars[i].vx = (1 + rand() % 15);
185 FlyStars[i].vy = -(1 + rand() % 15);
186 }
187 FlyStars[i].exist = true;
188 }
189 g_StarNum = FLYSTAR_NUMBER;
190 }
191
192 // 显示粒子
193 for (int i = 0; i < FLYSTAR_NUMBER; i++)
194 {
195 if (FlyStars[i].exist)
196 {
197 SelectObject(g_bufdc, g_hStar);
198 TransparentBlt(g_mdc, FlyStars[i].x, FlyStars[i].y, 30, 30, g_bufdc, 0, 0, 30, 30, RGB(0, 0, 0));
199
200 // 下一次坐标
201 FlyStars[i].x += FlyStars[i].vx;
202 FlyStars[i].y += FlyStars[i].vy;
203 // 在每进行一次贴图后,将粒子的存在时间累加1.
204 FlyStars[i].lasted++;
205 // 进行条件判断,若某粒子跑出窗口区域一定的范围,则将该粒子设为不存在,且粒子数随之递减
206 if (FlyStars[i].x <= -10 || FlyStars[i].x>g_rect.right || FlyStars[i].y <= -10 || FlyStars[i].y>g_rect.bottom || FlyStars[i].lasted>FLYSTAR_LASTED_FRAME)
207 {
208 FlyStars[i].exist = false; //删除星光粒子
209 g_StarNum--; //递减星光总数
210 }
211 }
212 }
213 BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
214 g_tPre = GetTickCount();
215 }
216
217 BOOL Game_CleanUp(HWND hwnd)
218 {
219 // 释放资源对象
220 DeleteObject(g_hBackGround);
221 DeleteObject(g_hStar);
222 DeleteDC(g_bufdc);
223 DeleteDC(g_mdc);
224 ReleaseDC(hwnd, g_hdc);
225 return TRUE;
226 }