当前位置:   article > 正文

C/C++实现球球大作战(高仿版),全源码分享带你轻松完成_球球大作战源码

球球大作战源码

每天一个C语言小项目,提升你的编程能力! 

 《球球大作战》虽然在玩法上类似于大球吃小球的模式看起来很单薄。但是在游戏过程中会出现无数种意外情况,这就需要玩家运用一系列策略来达到不被吃和吃掉别人球的目的,大大增加了游戏的耐玩性。

一个人的话想要实现复刻球球太困难了,所以这是仿照成熟版球球大作战写的简易版小游戏,有食物、敌人,甚至像和平精英一样加了一层外面的毒圈。

游戏操作起来很简单,用 A S D W 四个键控制球的移动方向。

地图大小是屏幕的16倍,吃完所有敌人就胜利。记住不要被敌人吃掉哦!

效果图展示:

完整的游戏源代码如下:

  1. #include <graphics.h>
  2. #include <conio.h>
  3. #include <time.h>
  4. #include <math.h>
  5. #include <wchar.h>
  6. #define WIDTH 1024 // 屏幕宽
  7. #define HEIGHT 576 // 屏幕高
  8. #define MAPW (WIDTH * 4) // 地图宽
  9. #define MAPH (HEIGHT * 4) // 地图高
  10. #define AINUM 100 // AI 数量
  11. #define FNUM 2000 // FOOD 数量
  12. #define PTIME 180 // 毒圈刷新时间
  13. #define DISTANCE(x1, y1, x2, y2) (sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)))
  14. struct FOOD
  15. {
  16. bool eat;
  17. COLORREF color; // 颜色
  18. int x, y; // 坐标
  19. char type;
  20. };
  21. struct BALL // 定义小球结构
  22. {
  23. bool life; // 生命
  24. COLORREF color; // 颜色
  25. int x, y; // 坐标
  26. float r; // 半径
  27. };
  28. FOOD food[FNUM]; // 食物
  29. BALL mover = { 1, RGB(0, 0, 0), 0, 0, 0 }; // 玩家
  30. BALL ai[AINUM] = { 1, RGB(0, 0, 0), 0, 0, 0 }; // 机器大军
  31. void move(BALL* ball); // 玩家移动
  32. void draw(); // 绘图
  33. void start(); // 游戏开始
  34. void setall(); // 初始化数据
  35. void AI(); // AI
  36. void Food(); // 食物
  37. void delay(DWORD ms); // 绝对延时
  38. DWORD* pBuffer; // 显示缓冲区指针
  39. int eaten = 0; // 吃 AI 的数量
  40. int ai_eaten = 0; // AI 吃 AI的数量
  41. int lx = -20, ly = MAPH + 20, rx = MAPW + 20, ry = -20; // 毒的位置
  42. int relx = -20, rely = MAPH + 20, rerx = MAPW + 20, rery = -20; // 毒的位置
  43. float asp = 1; // 缩放因子
  44. float Time = 0; // 时间
  45. int main()
  46. {
  47. initgraph(WIDTH, HEIGHT);
  48. start();
  49. setall(); // 游戏初始化
  50. BeginBatchDraw();
  51. while (true)
  52. {
  53. move(&mover); // 玩家移动
  54. AI();
  55. Food();
  56. draw(); // 绘图
  57. FlushBatchDraw(); // 显示缓存的绘制内容
  58. delay(20); // 绝对延迟
  59. }
  60. }
  61. void move(BALL* ball)
  62. {
  63. if (ball->r <= 0) ball->life = false;
  64. if (ball->life == false) // 判定游戏是否接束
  65. {
  66. HWND hwnd = GetHWnd();
  67. MessageBox(hwnd, _T("你被吃了"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION); // 结束
  68. closegraph();
  69. exit(0);
  70. }
  71. if (eaten + ai_eaten == AINUM) // 是否吃掉所以 AI
  72. {
  73. HWND hwnd = GetHWnd();
  74. MessageBox(hwnd, _T("恭喜过关"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION); // 结束
  75. closegraph();
  76. exit(0);
  77. }
  78. if (ball->x > (MAPW - ball->r) || ball->x - ball->r < 0 || ball->y - ball->r < 0 || ball->y >(MAPH - ball->r))
  79. ball->r -= 0.1f;
  80. for (int i = 0; i < AINUM; i++) // 玩家吃 AI 判定
  81. {
  82. if (ball->r >= ai[i].r)
  83. {
  84. if (ai[i].life == 0) continue;
  85. if (DISTANCE(ball->x, ball->y, ai[i].x, ai[i].y) < (4 / 5.0 * (ball->r + ai[i].r)))
  86. {
  87. ai[i].life = 0; // 吃掉
  88. ball->r += (ai[i].r * ai[i].r / 2) / ball->r; // 推理过程: pai * ball->r*ball->r += pai*ai[i].r*ai[i].r; πr*r=πr*r+πai[i].r*ai[i].r
  89. eaten++;
  90. }
  91. }
  92. }
  93. for (int n = 0; n < FNUM; n++) // 玩家吃食物
  94. {
  95. if (food[n].eat == 0) continue;
  96. if (DISTANCE(ball->x, ball->y, food[n].x, food[n].y) < ball->r)
  97. {
  98. ball->r += 4 / ball->r; // 增加面积
  99. food[n].eat = 0; // 食物被吃
  100. }
  101. }
  102. static int mx = 0, my = 0; // 记录偏移量
  103. if (GetAsyncKeyState(65) & 0x8000) { ball->x -= 2; mx += 2; } //左边
  104. if (GetAsyncKeyState(87) & 0x8000) { ball->y -= 2; my += 2; } //上面
  105. if (GetAsyncKeyState(83) & 0x8000) { ball->y += 2; my -= 2; } //下面
  106. if (GetAsyncKeyState(68) & 0x8000) { ball->x += 2; mx -= 2; } //右边
  107. setorigin(mx, my); // 坐标修正
  108. }
  109. void AI()
  110. {
  111. for (int i = 0; i < AINUM; i++)
  112. {
  113. if (ai[i].r > mover.r) // AI 吃玩家
  114. {
  115. if (DISTANCE(mover.x, mover.y, ai[i].x, ai[i].y) < 2 / 3.0 * ai[i].r + mover.r)
  116. {
  117. ai[i].r += (mover.r * mover.r) / ai[i].r;
  118. mover.life = 0;
  119. mover.r = 0;
  120. }
  121. }
  122. for (int j = 0; j < AINUM; j++) // AI 吃 AI
  123. {
  124. if (ai[i].r > ai[j].r)
  125. {
  126. if (ai[j].life == 0) continue;
  127. if (DISTANCE(ai[i].x, ai[i].y, ai[j].x, ai[j].y) < 4 / 5.0 * ai[i].r + ai[j].r)
  128. {
  129. ai[i].r += (ai[j].r * ai[j].r) / ai[i].r; // 面积增加
  130. ai[j].life = 0;
  131. ai[j].r = 0;
  132. ai_eaten++;
  133. }
  134. }
  135. }
  136. double min_DISTANCE = 100000;
  137. int min = -1;
  138. for (int k = 0; k < AINUM; k++) // AI 靠近 AI
  139. {
  140. if (ai[i].r > ai[k].r && ai[k].life == 1)
  141. {
  142. if (DISTANCE(ai[i].x, ai[k].x, ai[i].y, ai[k].y) < min_DISTANCE)
  143. {
  144. min_DISTANCE = DISTANCE(ai[i].x, ai[k].x, ai[i].y, ai[k].y);
  145. min = k;
  146. }
  147. }
  148. }
  149. if ((min != -1) && (rand() % 2 == 1))
  150. {
  151. if (rand() % 2)
  152. {
  153. if (ai[i].x < ai[min].x) ai[i].x++;
  154. else ai[i].x--;
  155. }
  156. else
  157. {
  158. if (ai[i].y < ai[min].y) ai[i].y++;
  159. else ai[i].y--;
  160. }
  161. }
  162. for (int n = 0; n < FNUM; n++) // AI 吃食物
  163. {
  164. if (food[n].eat == 0) continue;
  165. if (DISTANCE(ai[i].x, ai[i].y, food[n].x, food[n].y) < ai[i].r)
  166. {
  167. ai[i].r += 4 / ai[i].r;
  168. food[n].eat = 0;
  169. }
  170. }
  171. }
  172. }
  173. void Food()
  174. {
  175. for (int i = 0; i < FNUM; i++) // 食物重新生成
  176. {
  177. if (food[i].eat == 0)
  178. {
  179. food[i].eat = 1;
  180. food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
  181. food[i].x = rand() % MAPW;
  182. food[i].y = rand() % MAPH;
  183. food[i].type = rand() % 10 + 1;
  184. }
  185. }
  186. }
  187. void draw()
  188. {
  189. clearcliprgn();
  190. setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 20); // 改笔的颜色、状态
  191. setlinecolor(RGB(0, 100, 0));
  192. line(relx, rely, relx, rery); // 左竖
  193. line(relx, rely, rerx, rely); // 上横
  194. line(relx, rery, rerx, rery); // 下横
  195. line(rerx, rery, rerx, rely); // 右竖
  196. setfillcolor(GREEN);
  197. if (mover.x - 0.5 * WIDTH / asp < relx) floodfill(relx - 11, mover.y, RGB(0, 100, 0));
  198. if (mover.x + 0.5 * WIDTH / asp > rerx) floodfill(rerx + 11, mover.y, RGB(0, 100, 0));
  199. if (mover.y - 0.5 * HEIGHT / asp < rery) floodfill(mover.x, rery - 11, RGB(0, 100, 0));
  200. if (mover.y + 0.5 * HEIGHT / asp > rely) floodfill(mover.x, rely + 11, RGB(0, 100, 0));
  201. setlinecolor(WHITE); // 改笔颜色 状态
  202. setlinestyle(PS_NULL);
  203. for (int i = 0; i < FNUM; i++) // 画出食物
  204. {
  205. if (food[i].eat == 0) continue;
  206. setfillcolor(food[i].color);
  207. switch (food[i].type) // 形状
  208. {
  209. case 1: solidellipse(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4); break;
  210. case 2: solidellipse(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2); break;
  211. case 3: solidrectangle(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2); break;
  212. case 4: solidrectangle(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4); break;
  213. case 5: solidroundrect(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4, 2, 2); break;
  214. case 6: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 2); break;
  215. case 7: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 4, 2); break;
  216. case 8: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 4); break;
  217. case 9: solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 1, 1); break;
  218. case 10: fillcircle(food[i].x, food[i].y, 4); break;
  219. }
  220. }
  221. for (int i = 0; i < AINUM; i++) // 画 AI
  222. {
  223. if (ai[i].life == 0) continue;
  224. setfillcolor(ai[i].color);
  225. fillcircle(ai[i].x, ai[i].y, int(ai[i].r + 0.5));
  226. }
  227. setfillcolor(mover.color); // 画玩家
  228. fillcircle(mover.x, mover.y, int(mover.r + 0.5));
  229. IMAGE map(150, 100); // 小地图
  230. SetWorkingImage(&map);
  231. setbkcolor(RGB(120, 165, 209)); // 浅灰色背景
  232. cleardevice();
  233. for (int i = 0; i < AINUM; i++) // 画 AI
  234. {
  235. if (ai[i].life == 0) continue;
  236. setfillcolor(ai[i].color);
  237. fillcircle(ai[i].x * 150 / WIDTH / 4, ai[i].y * 100 / HEIGHT / 4, int(ai[i].r / 28 + 0.5));
  238. }
  239. setfillcolor(mover.color); // 画玩家
  240. fillcircle(mover.x * 150 / WIDTH / 4, mover.y * 100 / HEIGHT / 4, int(mover.r / 28 + 0.5));
  241. setlinecolor(RGB(0, 100, 0));
  242. if (lx != rx && ly != rx)
  243. {
  244. line(lx * 150 / WIDTH, ly * 100 / HEIGHT, lx * 150 / WIDTH, ry * 100 / HEIGHT); // 左竖
  245. line(lx * 150 / WIDTH, ly * 100 / HEIGHT, rx * 150 / WIDTH, ly * 100 / HEIGHT); // 上横
  246. line(lx * 150 / WIDTH, ry * 100 / HEIGHT, rx * 150 / WIDTH, ry * 100 / HEIGHT); // 下横
  247. line(rx * 150 / WIDTH, ry * 100 / HEIGHT, rx * 150 / WIDTH, ly * 100 / HEIGHT); // 右竖
  248. }
  249. setfillcolor(GREEN);
  250. floodfill(lx - 11, ly - 11, RGB(0, 100, 0));
  251. SetWorkingImage(); // 恢复绘图背景
  252. putimage(mover.x + int(0.5 * WIDTH) - 150, mover.y - int(0.5 * HEIGHT), 150, 100, &map, 0, 0); // 画出小地图
  253. setlinecolor(LIGHTBLUE); // 改笔颜色 状态
  254. setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 4);
  255. line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT), mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99); // 地图边框线
  256. line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99, mover.x + int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT) + 99); // 地图边框线
  257. setlinestyle(PS_NULL); // 恢复笔
  258. wchar_t str[32];
  259. swprintf_s(str, L"质量:%.1f 击杀:%d", mover.r, eaten);
  260. settextcolor(BLUE); // 改字体
  261. outtextxy(mover.x - int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT), str);
  262. settextcolor(BLUE); // 改字体
  263. outtextxy(mover.x - 36, mover.y - 8, _T("作者:无言"));
  264. }
  265. void setall()
  266. {
  267. srand((unsigned)time(NULL)); // 随机数
  268. mover.color = RGB(rand() % 256, rand() % 256, rand() % 256); // 随机颜色
  269. mover.life = 1; // 统统赋初值
  270. mover.x = int(WIDTH * 0.5);
  271. mover.y = int(HEIGHT * 0.5);
  272. mover.r = 20;
  273. for (int i = 0; i < AINUM; i++) // AI 的
  274. {
  275. ai[i].life = 1;
  276. ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
  277. ai[i].r = float(rand() % 10 + 10);
  278. ai[i].x = rand() % (MAPW - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);
  279. ai[i].y = rand() % (MAPH - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);
  280. }
  281. for (int i = 0; i < FNUM; i++) // 食物的
  282. {
  283. food[i].eat = 1;
  284. food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
  285. food[i].x = rand() % MAPW;
  286. food[i].y = rand() % MAPH;
  287. food[i].type = rand() % 10 + 1;
  288. }
  289. pBuffer = GetImageBuffer(NULL); // 获取显示缓冲区指针
  290. setbkcolor(WHITE); // 白色背景
  291. cleardevice(); // 初始化背景
  292. settextcolor(LIGHTRED); // 改字体
  293. setbkmode(TRANSPARENT);
  294. settextstyle(16, 0, _T("宋体"));
  295. }
  296. void delay(DWORD ms) // 绝对延时
  297. {
  298. static DWORD oldtime = GetTickCount();
  299. while (GetTickCount() - oldtime < ms)
  300. Sleep(1);
  301. oldtime = GetTickCount();
  302. }
  303. void start()
  304. {
  305. setbkcolor(WHITE); // 白色背景
  306. cleardevice(); // 初始化背景
  307. settextcolor(RED); // 改字体
  308. setbkmode(TRANSPARENT);
  309. settextstyle(128, 0, _T("宋体"));
  310. outtextxy(40, 20, _T("仿制球球大作战"));
  311. settextstyle(32, 0, _T("宋体"));
  312. outtextxy(740, 135, _T("Ver 1.6"));
  313. settextcolor(BLUE); // 改字体
  314. outtextxy(304, 240, _T("W上移 S下移 A左移 D右移"));
  315. outtextxy(112, 340, _T("躲避大球   追补小球   贪吃食物   增强实力"));
  316. settextcolor(BLACK); //改字体
  317. settextstyle(32, 0, _T("宋体"));
  318. outtextxy(384, 500, _T("按任意键开始游戏"));
  319. settextstyle(20, 0, _T("宋体"));
  320. outtextxy(810, 10, _T("作者粉丝群: 734106058"));
  321. _getch();
  322. }

大家赶紧去动手试试吧!

此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!

 整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在群里面交流提问编程问题哦!

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

(资料领取 ↓↓↓↓↓↓)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/764795
推荐阅读
相关标签
  

闽ICP备14008679号