1 实验内容

本实验主要是实现简单的飞机大战游戏,包含游戏声音、碰撞后爆炸效果,有大小敌机等。所用到的知识点如下:

1.贴图技术

2.飞机类、子弹类实现

3.位图移动

4.碰撞判断,实现爆炸效果

5.插入声音

此实验的大概设计:游戏画面保持有一架大敌机,五架小敌机,一架战机,30颗子弹。如果子弹击落了敌机,那么敌机对象不会被delete,而仅仅是改变它的位置,让它重新从上面飞下,姑且可以叫做“假摧毁”吧。同理,子弹飞出界面或打到敌机,该子弹对象也不会被delete,而是从底部重新上升。击落敌机时会有爆炸效果;战机被敌机摧毁会有更大的爆炸效果,且游戏会停1秒再继续。

2 实验环境

win10+vs2015

3 实验步骤

3.1 添加游戏资源

从网上下载自己喜欢的飞机和子弹图片(.png文件),下载游戏背景音乐(.wav文件),把上述资源导入本工程的res文件,复制res文件到Debug文件中,这样便可以直接打开zsr_简单飞机大战.exe

打开res文件,可以看到下图(当然啦,飞机、子弹和游戏声音选你喜欢的就行啦,不用跟我的一样):

上图中倒数第二个黑色的飞机就是我的程序图标。

3.2 修改程序图标

点击[这里]了解一下。

3.3 设置类

右键‘项目’,点击‘添加类’,就可以添加类啦。本实验设置4个类:大敌机(DADIJI),小敌机(XIAODIJI),战机(ZHANJI),子弹(ZIDAN)。并且在类中实现贴图。

3.3.1 大敌机类(DADIJI)

添加大敌机类,类名为'DADIJI'。并在类中添加数据成员和成员函数,修改构造函数。具体如下:

  1. //在类中加入:
  2. CImage m_hero;//图片类对象
  3. int diji_x;//图片横坐标
  4. int diji_y;//图片轴坐标
  5. void JIDRAW(CDC *cDC) { //设定大敌机的大小
  6. m_hero.Draw(*cDC, diji_x, diji_y, 100, 50);//图片的宽为100,高50
  7. }
  8. //修改构造函数
  9. DADIJI::DADIJI()
  10. {
  11. //加载图片
  12. CString imgPath = _T("res\\LXPlane.png");
  13. m_hero.Load(imgPath);
  14. //初始化大敌机的位置
  15. diji_x = 300;
  16. diji_y = 0;
  17. }

3.3.2 小敌机类(XIAODIJI)

添加内容和大敌机类似,如下:

  1. //类中加入:
  2. CImage m_hero;
  3. int diji_x;
  4. int diji_y;
  5. //设定小敌机的大小
  6. void JIDRAW(CDC *cDC) {
  7. m_hero.Draw(*cDC, diji_x, diji_y, 50,50); //小敌机宽50,高50
  8. }
  9. //修改构造函数:
  10. XIAODIJI::XIAODIJI()
  11. {
  12. //加载图片
  13. CString imgPath = _T("res\\BluePlane.png");
  14. m_hero.Load(imgPath);
  15. //设定小敌机的初始位置
  16. diji_x = 30;
  17. diji_y = 0;
  18. }

3.3.3 战机类(ZHANJI)

修改内容和大敌机差不多。这里说明一下,我的战机位置也用了diji_x和diji_y来表示,其实为了代码的可读性,这里用zhanji_x和zhanji_y比较好。(但我比较懒,这里就不修改了。)具体改动的代码如下:

  1. //在类中加入:
  2. CImage m_hero;
  3. int diji_x;
  4. int diji_y;
  5. CImage m_hero1;
  6. //设定战机的大小
  7. void JIDRAW(CDC *cDC) {
  8. m_hero.Draw(*cDC, diji_x, diji_y, 80, 80);
  9. }
  10. //加入爆炸效果函数
  11. void JIDRAW1(CDC *cDC, int x, int y) {
  12. m_hero1.Draw(*cDC, x, y, 100, 100);//战机被敌机碰撞将变成爆炸状
  13. }
  14. //修改构造函数:
  15. ZHANJI::ZHANJI()
  16. {
  17. //加载战机图片
  18. CString imgPath = _T("res\\XPlane.png");
  19. m_hero.Load(imgPath);
  20. //加载爆炸图片
  21. CString imgPath1 = _T("res\\ZHANJIBAOZHA.png");
  22. m_hero1.Load(imgPath1);
  23. //设定战机的初始位置
  24. diji_x = 330;
  25. diji_y = 500;
  26. }

3.3.4 子弹类(ZIDAN)

这里的解释,和战机类的解释一样。具体代码如下:

  1. //在类中加入:
  2. CImage m_hero;
  3. CImage m_hero1;
  4. int diji_x;
  5. int diji_y
  6. //设置子弹的大小;
  7. void JIDRAW(CDC *cDC) {
  8. m_hero.Draw(*cDC, diji_x, diji_y, 20, 20);
  9. }
  10. //设置爆炸效果
  11. void JIDRAW1(CDC *cDC,int x,int y) {
  12. m_hero1.Draw(*cDC, x, y, 50, 50);//子弹碰到敌机,将会变成爆炸状
  13. }
  14. 修改构造函数:
  15. ZIDAN::ZIDAN()
  16. {
  17. //加载子弹图片
  18. CString imgPath = _T("res\\zidan.png");
  19. m_hero.Load(imgPath);
  20. //加载爆炸图片
  21. CString imgPath1 = _T("res\\baozha.png");
  22. m_hero1.Load(imgPath1);
  23. 设定子弹初始位置
  24. diji_x = 320;
  25. diji_y = 600;
  26. }

3.4 游戏重要变量

  1. //在view类中加入下面变量:
  2. DADIJI DA1;//大敌机1台
  3. XIAODIJI XIAO1[5];//保持游戏界面有小敌机5台
  4. ZIDAN ZI[30];//保持游戏界面有子弹30颗
  5. ZHANJI ZHAN;//战机一台

3.5 设计游戏开始界面

  1. //修改view中的Oncreat()函数,如下:
  2. int Czsr_简单飞机大战View::OnCreate(LPCREATESTRUCT lpCreateStruct)
  3. {
  4. if (CView::OnCreate(lpCreateStruct) == -1)
  5. return -1;
  6. // TODO: 在此添加您专用的创建代码
  7. PlaySound(_T("res\\youxi.wav"), NULL, SND_FILENAME | SND_ASYNC|SND_LOOP);//循环播放背景音乐
  8. this->SetTimer(1, 100, NULL);//设置一个定时器
  9. int x_num = 30;
  10. for (int j3 = 0;j3 < 5;j3++)
  11. {
  12. XIAO1[j3].diji_x += x_num;//开始时,小飞机的横坐标相隔30
  13. x_num += 30;
  14. XIAO1[j3].diji_y -= x_num;//开始时,小飞机的纵坐标相隔30,起到延迟出现的效果
  15. }
  16. int num = 0;
  17. for (int j2 = 0;j2 < 30;j2++)
  18. {
  19. ZI[j2].diji_y-= num;//开始时,子弹的纵坐标相隔25,起到延迟出现的效果
  20. ZI[j2].diji_x = ZHAN.diji_x+30;//子弹的横坐标在战机的正中间
  21. num += 25;
  22. ;
  23. }
  24. return 0;
  25. }

3.6 位图移动和碰撞

看到3.5的修改中已经设置了一个计时器,这里响应Ontimer()函数,如下:

  1. //设计ontimer()函数(如下):
  2. void Czsr_简单飞机大战View::OnTimer(UINT_PTR nIDEvent)
  3. {
  4. // TODO: 在此添加消息处理程序代码和/或调用默认值
  5. CDC *cDC = this->GetDC(); //获得当前窗口的DC
  6. GetClientRect(&m_client); //获得窗口的尺寸
  7. CRect rect;
  8. GetClientRect(rect);
  9. cDC->FillSolidRect(rect, RGB(255, 255, 255));
  10. ZHAN.JIDRAW(cDC);//画战机
  11. //子弹
  12. for (int j1 = 0;j1 < 30;j1++)
  13. {
  14. if (ZI[j1].diji_x < DA1.diji_x+100&& ZI[j1].diji_x >DA1.diji_x - 100&&ZI[j1].diji_y < DA1.diji_y+50&& ZI[j1].diji_y >DA1.diji_y - 50)//判断子弹是否和大战机碰撞
  15. {
  16. int xx = DA1.diji_x;
  17. int yy = DA1.diji_y;
  18. ZI[j1].JIDRAW1(cDC,xx,yy );//若两者产生碰撞,则出现爆炸效果
  19. ZI[j1].diji_y = ZHAN.diji_y;
  20. ZI[j1].diji_x = ZHAN.diji_x + 30;//发生爆炸的子弹,重新回到战机的子弹口
  21. DA1.diji_x = rand() % 400; //大敌机从上面的随机位置重新出现
  22. while (DA1.diji_x<20)
  23. DA1.diji_x = rand() % 400;
  24. DA1.diji_y = 0;
  25. }
  26. else if (ZI[j1].diji_y < 0)//如果子弹飞到最高处,重回战机子弹口
  27. {
  28. ZI[j1].diji_y = ZHAN.diji_y;
  29. ZI[j1].diji_x = ZHAN.diji_x + 30;
  30. }
  31. else
  32. ZI[j1].diji_y = ZI[j1].diji_y-10;//否则,继续上升
  33. for (int i1 = 0;i1 < 5;i1++)
  34. {
  35. if (ZI[j1].diji_x < XIAO1[i1].diji_x + 50 && ZI[j1].diji_x >XIAO1[i1].diji_x - 50 && ZI[j1].diji_y <XIAO1[i1].diji_y + 50 && ZI[j1].diji_y >XIAO1[i1].diji_y - 50)//判断每台小敌机是否和子弹碰撞
  36. {
  37. int xx1 = XIAO1[i1].diji_x;
  38. int yy1 = XIAO1[i1].diji_y;
  39. XIAO1[i1].diji_x = rand() % 400;//若碰撞,小敌机重新从上面的随机位置降落
  40. while (XIAO1[i1].diji_x<20)
  41. XIAO1[i1].diji_x = rand() % 400;
  42. XIAO1[i1].diji_y = -30;
  43. ZI[j1].JIDRAW1(cDC, xx1, yy1);//爆炸状态
  44. ZI[j1].diji_y = ZHAN.diji_y;
  45. ZI[j1].diji_x = ZHAN.diji_x + 30;//子弹重新回到战机子弹口
  46. }
  47. }
  48. ZI[j1].JIDRAW(cDC);//画子弹
  49. }
  50. //小敌机
  51. for (int j = 0;j < 5;j++)
  52. {
  53. if (ZHAN.diji_x < XIAO1[j].diji_x + 50 && ZHAN.diji_x >XIAO1[j].diji_x -50 && ZHAN.diji_y < XIAO1[j].diji_y + 50 && ZHAN.diji_y >XIAO1[j].diji_y - 50)//判断战机是否和小战机碰撞
  54. {
  55. int xxx = ZHAN.diji_x;
  56. int yyy = ZHAN.diji_y;
  57. ZHAN.JIDRAW1(cDC, xxx, yyy);//若碰撞,发生战机爆炸
  58. Sleep(500);//停止500ms
  59. XIAO1[j].diji_x = rand() % 400;
  60. while (DA1.diji_x<20)
  61. XIAO1[j].diji_x = rand() % 400;//小敌机重新随机降落
  62. DA1.diji_y = 0;
  63. ZHAN.diji_x = 300;
  64. ZHAN.diji_y = 500;//战机回到初始位置
  65. }
  66. else if (XIAO1[j].diji_y > 690)//若小敌机走出游戏界面,则重新随机降落
  67. {
  68. XIAO1[j].diji_x = rand() % 400;
  69. while(XIAO1[j].diji_x<20)
  70. XIAO1[j].diji_x = rand() % 400;
  71. XIAO1[j].diji_y = 0;
  72. }
  73. XIAO1[j].diji_y += 10;//小战机下降
  74. XIAO1[j].JIDRAW(cDC);
  75. }
  76. //大敌机
  77. if (ZHAN.diji_x < DA1.diji_x + 100 && ZHAN.diji_x >DA1.diji_x - 100 && ZHAN.diji_y < DA1.diji_y + 80 && ZHAN.diji_y >DA1.diji_y - 80)//判断战机是否和大敌机发生碰撞
  78. {
  79. int xxx = ZHAN.diji_x;
  80. int yyy = ZHAN.diji_y;
  81. ZHAN.JIDRAW1(cDC, xxx, yyy);//若碰撞,战机爆炸,大敌机重新随机降落
  82. Sleep(500);//停止500ms
  83. DA1.diji_x = rand() % 400;
  84. while (DA1.diji_x<20)
  85. DA1.diji_x = rand() % 400;
  86. DA1.diji_y = 0;
  87. ZHAN.diji_x = 300;//战机回到初始位置
  88. ZHAN.diji_y = 500;
  89. }
  90. if (DA1.diji_y < 650)//大敌机下降
  91. DA1.diji_y = DA1.diji_y + 10;
  92. else
  93. DA1.diji_y = 0;//若大飞机飞出游戏界面 ,重新随机降落
  94. DA1.JIDRAW(cDC); //画大敌机
  95. ReleaseDC(cDC);
  96. CView::OnTimer(nIDEvent);
  97. }

3.7 战机移动

为方便,这里的战机只能左右移动。下面响应一个键盘左右键的函数:

  1. void Czsr_简单飞机大战View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  2. {
  3. // TODO: 在此添加消息处理程序代码和/或调用默认值
  4. if (nChar == 37)//向左移
  5. {
  6. if (ZHAN.diji_x > 0)
  7. ZHAN.diji_x -= 10;
  8. }
  9. else
  10. {
  11. if (nChar == 39)//向右移
  12. if (ZHAN.diji_x <450)
  13. ZHAN.diji_x += 10;
  14. }
  15. CView::OnKeyDown(nChar, nRepCnt, nFlags);
  16. }

3.8 删除状态栏

在框架类的OnCreate()函数中删除响应代码即可。

3.9  删除菜单栏,固定窗口大小

  1. 修改框架类的PreCreateWindow()函数:
  2. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
  3. {
  4. if( !CFrameWnd::PreCreateWindow(cs) )
  5. return FALSE;
  6. // TODO: 在此处通过修改
  7. // CREATESTRUCT cs 来修改窗口类或样式
  8. //zsr,删除菜单项
  9. cs.hMenu = NULL;
  10. //禁止改变窗口大小
  11. cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
  12. cs.style &= ~WS_MAXIMIZEBOX; //禁止窗口最大化
  13. cs.style &= ~WS_MINIMIZEBOX; //禁止窗口最小化
  14. cs.style &= ~WS_THICKFRAME;//使窗口不能用鼠标改变大小
  15. return TRUE;
  16. }

4 游戏展示

初始样式                                                                    游戏中

小敌机爆炸                                                                 大敌机、战机爆炸

5 总结

这个实验太过简单,飞机数量已经固定且没有计分功能。

MFC实现简单飞机大战(含游戏声音)的更多相关文章

  1. canvas绘制“飞机大战”小游戏,真香!

    canvas是ArkUI开发框架里的画布组件,常用于自定义绘制图形.因为其轻量.灵活.高效等优点,被广泛应用于UI界面开发中. 本期,我们将为大家介绍canvas组件的使用. 一.canvas介绍 1 ...

  2. android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)

    序言作为一个android开发人员,时常想开发一个小游戏娱乐一下大家,今天就说说,我是怎么样一天写出一个简单的"飞机大战"的. 体验地址:http://www.wandoujia. ...

  3. [知了堂学习笔记]_纯JS制作《飞机大战》游戏_第1讲(实现思路与游戏界面的实现)

    整体效果展示: 一.实现思路 如图,这是我完成该项目的一个逻辑图,也是一个功能模块完成的顺序图. 游戏界面的完成 英雄飞机对象实现,在实现发射子弹方法过程中,又引出了子弹对象并实现.在此时,英雄飞机能 ...

  4. 用面向对象的编程方式实现飞机大战小游戏,java版

    概述 本文将使用java语言以面向对象的编程方式一步一步实现飞机大战这个小游戏 本篇文章仅供参考,如有写的不好的地方或者各位读者哪里没看懂可以在评论区给我留言 或者邮件8274551712@qq.co ...

  5. IOS学习之路五(SpriteKit 开发飞机大战小游戏一)

    参考SpriteKit 创建游戏的教程今天自己动手做了一下,现在记录一下自己怎么做的,今天之做了第一步,一共有三个部分. 第一步,项目搭建. 项目所用图片资源:点击打开链接 1.在Xcode打开之后, ...

  6. [知了堂学习笔记]_纯JS制作《飞机大战》游戏_第2讲(对象的实现及全局变量的定义)

    整体展示: 一.全局变量 /*===================玩家参数==========================*/ var myPlane; //英雄对象 var leftbtn = ...

  7. docker项目——搭建飞机大战小游戏

    项目2:搭建打飞机小游戏,验证数据持久化(最底下有链接) 第一步:拉取镜像 [root@localhost docker-image]# docker load < httpd_img.tar. ...

  8. [知了堂学习笔记]_纯JS制作《飞机大战》游戏_第3讲(逻辑方法的实现)

    整体展示: 上一讲实现了诸多对象,这次我们就需要实现许多逻辑方法,如控制飞机移动,判断子弹击中敌机,敌机与英雄飞机相撞等等.并且我们在实现这些功能的时候需要计时器去调用这些方法.setInterval ...

  9. javascript飞机大战-----009游戏结束

    /* 游戏引擎 */ var Engine = { //刚开始的游戏状态 gameStatus:false, //所以敌机 enemy:{}, //子弹 bullet:{}, //得分 scroe:0 ...

随机推荐

  1. python学习笔记1--python简介

    Python翻译中文是蟒蛇.发明人guido喜欢蟒蛇马戏团,故起名python. python发展简史: --CNRI时期.CNRI资助Python发展的重要单位,python1.5版之前的成果大部分 ...

  2. 如何使用VMWare共享Win7中的文件夹,对应Linux中的哪个目录下面?

    访问 /mnt/hgfs/你设置的共享名,如果找不到这个hgfs这个文件夹,那说明你还没正确安装好 install VMware tools

  3. AJax与Jsonp跨域访问

    一.JavaScript的AJax AJAX即"Asynchronous Javascript And XML"(异步JavaScript和XML) 设计AJax使用的一种重要技术 ...

  4. InnoDB: auto-extending data file ./ibdata1 is of a different size 640 pages (rounded down to MB) than specified in the .cnf file: initial 768 pages, max 0 (relevant if non-zero) pages!

    问题描述: centos 安装MySQL $yum install mysql-server 安装之后执行命令mysql 报错: 查看mysql的启动日志: [ERROR] InnoDB: auto- ...

  5. datatable.js 服务端分页+fixColumns列固定

    前言 记得还是15年的时候,工作需要,独自写后台管理系统..记得那时候,最让我头疼的不是后台逻辑,而是数据的列表展示. 列很多的时候,页面显示问题;分页样式问题;表格样式问题;数据加载...很多细节的 ...

  6. Expectation Maximization(EM)算法note

    EM算法,之前上模式识别课上,推导过,在<统计学习方法>中没耐性的看过几次,个人感觉讲的过于理论,当时没怎么看懂,后来学lda,想要自己实现一下em算法,又忘记了,看来还是学的不够仔细,认 ...

  7. DevelopmentValue

    DevelopmentValue mysql为utf8为什么网页返回数据及写入mysql数据库均为乱码? eclipse运行配了maven之后,创建包也弹出这个错误,每次都弹 c语言怎么建立txt文件 ...

  8. JAVA源文件中是否可以包括多个类,有什么限制

    JAVA源文件中是否可以包括多个类,有什么限制 解答:一个java源文件中可以包含多个类,每个源文件中至多有一个public类,如果有的话,那么源文件的名字必须与之相同.如果源文件中没有public类 ...

  9. SRM 719 Div 1 250 500

    250: 题目大意: 在一个N行无限大的网格图里,每经过一个格子都要付出一定的代价.同一行的每个格子代价相同. 给出起点和终点,求从起点到终点的付出的最少代价. 思路: 最优方案肯定是从起点沿竖直方向 ...

  10. js阻止表单提交

    <!DOCTYPE html><html><head>    <title>Simple Login Form</title>    < ...