Windows粒子系统
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 }