当前位置:   article > 正文

飞机大战——C语言(附源码)_c语言编程飞机大战素材

c语言编程飞机大战素材

概要

声明:本文大部分内容参考up主进行编写(C语言飞机大战

并对他没有讲解到的进行延续,以及本人编写时遇到的诸多问题。

整体架构流程

1.准备飞机大战所需素材,并预装esayx第三方图形库

2.游戏窗口创建及游戏角色的的创建

3.游戏角色的移动

4.对游戏角色进行移动边界限制

5.玩家飞机子弹的的发射与移动

6.大量敌机的绘制与移动

7.定时器的设置

8.背景音乐及得分面板的输出

技术名词解释

所需函数

  •  initgraph(宽 , 高 , SHOWCONSOLE) //绘制游戏窗口
  • loadimage(&图片 , _T("图片路径"))   //加载图片
  • putimage(x坐标 , y坐标, &img_palyer[0] , NOTSRCERASE) //对窗口进行贴图
  • putimage(x坐标 , y坐标, &img_palyer[1] , SRCINVERT) //并进行掩码处理
  • mciSendString(LPCSTR("open 路径 alias BGM"), 0, 0, 0); //音乐调用
  • outtextxy(宽 * 0.5, 高 * 0.9, _T("得分:")) //得分板绘制
  • 使用ps进行掩码图绘制

技术细节

编程过程中遇到的一些棘手问题:

  • 基础准备:字符集要使用多字节字符集;SDL检查改为否;链接器输入依赖库导入winmm.lib静态库。
  • 头文件准备 #include<Windows>  //调用windows 的API
                       #include<mmsystem.h> //多媒体接口
                      #pragma comment(lib,"winmm.lib") //导入静态库
  • 音乐文件可能直接改后缀没有用,本人就是到QQ音乐转格式才通过编译
  • mciSendString调用时,我使用repeat编译通过,但无法发出声音,看了许多大佬解释,都没有用,后面我朋友看了微软手册给我说可能重复了,mciSendString执行了两次,意思就是音乐一直从0h0m0s开始循环,然后让我加个全局变量控制,果然好了:                                         代码如://控制音乐的全局变量                                                                                                 short static
     shortCommandRunCounterr = 0;                                                                             if (shortCommandRunCounterr == 0)
    {
        shortCommandRunCounterr++;                                                                                                 //加入  mciSendString(LPCSTR("open ./music/game_music.mp3 alias BGM"), 0, 0, 0);            我源码已经封装函数了                                                                                                                 mciSendString(LPCSTR("play BGM repeat"), 0, 0, 0); //此时就不会重复                               }  这个问题真的让我苦恼了好久
  • 得分板的绘制时,高版本vs建议用_stprintf_s(swprintf_s可能不可用)
  • 碰撞检测的判定
  • 在转exe时需要强制转换音乐类型(源码中是我已经转过了)
  • loadimage也需要加_T转换
  • 以上就是我编写时遇到的一些比较麻烦的题,重点建议编写程序加入日志,这样可以方便寻找错误,并进行分析,我的源码就是因为没有加日志,找音乐错误找了很久。

小结

附源代码(底层)

  1. #include<stdio.h>
  2. #include<conio.h>
  3. #include<Windows.h>
  4. //多媒体接口
  5. #include<mmsystem.h>
  6. //导入静态库
  7. #pragma comment(lib,"winmm.lib")
  8. #include<time.h>
  9. //图形库,预装第三方库 easyX
  10. #include<graphics.h>
  11. enum My
  12. {
  13. WIDTH = 480, //窗口高度
  14. HEIGHT = 700,
  15. BULLLET_NUM = 15,//子弹数量
  16. ENEMY_NUM = 10, //敌机数量
  17. BIG, //敌机类型
  18. SMALL
  19. };
  20. //飞机结构
  21. struct Plane
  22. {
  23. int x;
  24. int y;
  25. int live; //是否存活
  26. int width;
  27. int height;
  28. int hp;
  29. int type; //敌机类型
  30. }player , bull[BULLLET_NUM] , enemy[ENEMY_NUM];
  31. //保存背景图片
  32. IMAGE bk;
  33. //保存玩家图片
  34. IMAGE img_palyer[2];
  35. //保存子弹图片
  36. IMAGE img_bull[2];
  37. //保存敌机图片
  38. IMAGE img_enemy[2][2];
  39. //得分板
  40. int score = 0;
  41. //控制音乐的全局变量
  42. short static
  43. shortCommandRunCounterr = 0;
  44. //音乐文件管理
  45. void openMusic()
  46. {
  47. //背景音效
  48. mciSendString(LPCSTR("open ./music/game_music.mp3 alias BGM"), 0, 0, 0);
  49. //子弹音效
  50. mciSendString(LPCSTR("open ./music/bullet.mp3 alias blow"), 0, 0, 0);
  51. //撞击音效
  52. mciSendString(LPCSTR("open ./music/enemy3_down.mp3 alias collide"), 0, 0, 0);
  53. //击中音效
  54. mciSendString(LPCSTR("open ./music/get_bomb.mp3 alias hit"), 0, 0, 0);
  55. }
  56. //加载游戏背景图片和音乐
  57. void loadpicture()
  58. {
  59. //加载背景图
  60. loadimage(&bk , _T("./images/background.png"));
  61. //加载玩家
  62. loadimage(&img_palyer[0], _T("./images/me1.jpg"));
  63. loadimage(&img_palyer[1], _T("./images/me2.jpg"));
  64. //加载子弹
  65. loadimage(&img_bull[0], _T("./images/bullet1.jpg"));
  66. loadimage(&img_bull[1], _T("./images/bullet2.jpg"));
  67. //加载敌机
  68. loadimage(&img_enemy[0][0], _T("./images/enemy1.jpg"));
  69. loadimage(&img_enemy[0][1], _T("./images/enemy2.jpg"));
  70. loadimage(&img_enemy[1][0], _T("./images/enemy3_n1.jpg"));
  71. loadimage(&img_enemy[1][1], _T("./images/enemy3_n2.jpg"));
  72. //加载音乐
  73. openMusic();
  74. if (shortCommandRunCounterr == 0)
  75. {
  76. shortCommandRunCounterr++;
  77. mciSendString(LPCSTR("play BGM repeat"), 0, 0, 0); //循环播放
  78. }
  79. }
  80. //敌机类型初始化
  81. void enemyHp(int i)
  82. {
  83. if (rand() % 10 == 0)
  84. {
  85. enemy[i].type = BIG;
  86. enemy[i].hp = 3;
  87. enemy[i].width = 169;
  88. enemy[i].height = 258;
  89. }
  90. else
  91. {
  92. enemy[i].type = SMALL;
  93. enemy[i].hp = 1;
  94. enemy[i].width = 57;
  95. enemy[i].height = 43;
  96. }
  97. }
  98. void gameInit()
  99. {
  100. player.x = WIDTH / 2;
  101. player.y = HEIGHT - 120;
  102. player.live = true;
  103. //初始化子弹
  104. for (int i = 0 ; i < BULLLET_NUM ; i++)
  105. {
  106. bull[i].x = 0;
  107. bull[i].y = 0;
  108. bull[i].live = false;
  109. }
  110. //初始化敌机
  111. for (int i = 0; i < ENEMY_NUM; i++)
  112. {
  113. enemy[i].live = false;
  114. enemyHp(i);
  115. }
  116. }
  117. //游戏绘制函数
  118. void gameDraw()
  119. {
  120. loadpicture();
  121. //贴背景
  122. putimage(0, 0, &bk);
  123. //贴玩家
  124. putimage(player.x , player.y, &img_palyer[0] , NOTSRCERASE);
  125. putimage(player.x , player.y, &img_palyer[1] , SRCINVERT);
  126. //贴子弹
  127. for (int i = 0; i < BULLLET_NUM; i++)
  128. {
  129. if (bull[i].live)
  130. {
  131. putimage(bull[i].x, bull[i].y, &img_bull[0], NOTSRCERASE);
  132. putimage(bull[i].x, bull[i].y, &img_bull[1], SRCINVERT);
  133. }
  134. }
  135. //贴敌机
  136. for (int i = 0; i < ENEMY_NUM; i++)
  137. {
  138. if (enemy[i].live)
  139. {
  140. if (enemy[i].type == BIG)
  141. {
  142. putimage(enemy[i].x, enemy[i].y, &img_enemy[1][0], NOTSRCERASE);
  143. putimage(enemy[i].x, enemy[i].y, &img_enemy[1][1], SRCINVERT);
  144. }
  145. else
  146. {
  147. putimage(enemy[i].x, enemy[i].y, &img_enemy[0][0], NOTSRCERASE);
  148. putimage(enemy[i].x, enemy[i].y, &img_enemy[0][1], SRCINVERT);
  149. }
  150. }
  151. }
  152. //绘制得分板
  153. outtextxy(WIDTH * 0.5, HEIGHT * 0.9, _T("得分:"));
  154. TCHAR s[5];
  155. _stprintf_s(s, _T("%d"), score);
  156. outtextxy(WIDTH * 0.6, HEIGHT * 0.9, s);
  157. }
  158. //创建子弹
  159. void createBullet()
  160. {
  161. for (int i = 0; i < BULLLET_NUM; i++)
  162. {
  163. if (!bull[i].live)
  164. {
  165. bull[i].x = player.x+50;
  166. bull[i].y = player.y;
  167. bull[i].live = true;
  168. break;
  169. }
  170. }
  171. }
  172. //子弹移动
  173. void bulletMove(int speed)
  174. {
  175. for (int i = 0; i < BULLLET_NUM; i++)
  176. {
  177. if (bull[i].live)
  178. {
  179. bull[i].y -= speed;
  180. if (bull[i].y < 0)
  181. {
  182. bull[i].live = false;
  183. }
  184. }
  185. }
  186. }
  187. //使用定时器让敌机均匀下落
  188. bool timer(int ms, int id)
  189. {
  190. static DWORD t[10];
  191. if (clock() - t[id] > ms)
  192. {
  193. t[id] = clock();
  194. return true;
  195. }
  196. return false;
  197. }
  198. //角色移动 && 子弹移动
  199. void playerMove(int speed)
  200. {
  201. //使用windows函数 GetAsyncKeyState
  202. if (GetAsyncKeyState(VK_UP) || GetAsyncKeyState('W'))
  203. {
  204. if(player.y > 0 )
  205. player.y -= speed;
  206. }
  207. if (GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState('S'))
  208. {
  209. if (player.y+60 < HEIGHT)
  210. player.y += speed;
  211. }
  212. if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState('A'))
  213. {
  214. if (player.x+50 > 0)
  215. player.x -= speed;
  216. }
  217. if (GetAsyncKeyState(VK_RIGHT) || GetAsyncKeyState('D'))
  218. {
  219. if (player.x+50 < WIDTH)
  220. player.x += speed;
  221. }
  222. //使用封装函数定时器解决子弹移动
  223. if (GetAsyncKeyState(VK_SPACE) && timer(200 , 1))
  224. {
  225. //调用函数创建一个子弹
  226. createBullet();
  227. //播放子弹音效
  228. mciSendString(LPCSTR("close blow"), 0, 0, 0);
  229. openMusic();
  230. mciSendString(LPCSTR("play blow"), 0, 0, 0);
  231. }
  232. }
  233. //产生敌机
  234. void createEnemy()
  235. {
  236. for (int i = 0; i < ENEMY_NUM; i++)
  237. {
  238. if (!enemy[i].live)
  239. {
  240. enemy[i].live = true;
  241. enemy[i].x = rand() % (WIDTH / 2);
  242. enemy[i].y = 0;
  243. enemyHp(i);
  244. break;
  245. }
  246. }
  247. }
  248. //敌机的移动
  249. void enemyMove(int speed)
  250. {
  251. for (int i = 0; i < ENEMY_NUM; i++)
  252. {
  253. if (enemy[i].live)
  254. {
  255. enemy[i].y += speed;
  256. if (enemy[i].y > HEIGHT)
  257. {
  258. enemy[i].live = false;
  259. }
  260. }
  261. }
  262. }
  263. //打飞机检测
  264. void playPlance()
  265. {
  266. for (int i = 0; i < ENEMY_NUM; i++)
  267. {
  268. if (!enemy[i].live)
  269. continue;
  270. for (int k = 0; k < ENEMY_NUM; k++)
  271. {
  272. if (!bull[k].live)
  273. continue;
  274. //子弹碰撞检测
  275. if (bull[k].x > enemy[i].x && bull[k].x < enemy[i].x + enemy[i].width
  276. && bull[k].y>enemy[i].y && bull[k].y < enemy[i].y + enemy[i].height)
  277. {
  278. score++;
  279. //播放击中音效
  280. mciSendString(LPCSTR("close hit"), 0, 0, 0);
  281. openMusic();
  282. mciSendString(LPCSTR("play hit"), 0, 0, 0);
  283. bull[k].live = false;
  284. enemy[i].hp--;
  285. }
  286. }
  287. //飞机碰撞检测
  288. if (player.x > enemy[i].x && player.x < enemy[i].x + enemy[i].width
  289. && player.y>enemy[i].y && player.y < enemy[i].y + enemy[i].height)
  290. {
  291. player.live = false;
  292. //播放碰撞音效
  293. mciSendString(LPCSTR("close collide"), 0, 0, 0);
  294. openMusic();
  295. mciSendString(LPCSTR("play collide"), 0, 0, 0);
  296. }
  297. if (enemy[i].hp <= 0 || !player.live)
  298. {
  299. enemy[i].live = false;
  300. }
  301. }
  302. }
  303. //主函数
  304. int main()
  305. {
  306. //创建一个窗口
  307. initgraph(WIDTH , HEIGHT , SHOWCONSOLE);
  308. gameInit();
  309. //双缓冲绘图
  310. BeginBatchDraw();
  311. while (1)
  312. {
  313. gameDraw();
  314. playerMove(2);
  315. bulletMove(4);
  316. //使用定时器让敌机均匀下落
  317. if (timer(200 , 0))
  318. {
  319. createEnemy();
  320. }
  321. if (timer(5, 2))
  322. {
  323. enemyMove(1);
  324. }
  325. playPlance();
  326. FlushBatchDraw();
  327. }
  328. EndBatchDraw();
  329. return 0;
  330. }

可根据需要进行修改。

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

闽ICP备14008679号