这是基于MFC下的坦克大战游戏,编程工具使用VC++6.0。

下面将详细介绍如何一步一步实现坦克大战小游戏。

1.新建MFC工程

新建一个MFC工程,应用程序类型选择单文档类型,点击完成即可。

2.新建坦克大战类

3.定义结构体及变量

根据分析可知,坦克大战游戏主要有三个部分,即坦克,敌机,子弹。故在类的头文件中定义相应的结构体和变量。

由于坦克只有一个,敌机和子弹有多个,因此敌机和子弹使用结构体定义,坦克使用变量定义。在TanKeWar.h添加代码具体如下

typedef struct
{int x;//敌机坐标xint y;//敌机坐标yint v;//敌机速度int Size;//敌机大小int FS;//敌机分数
}DiJi;
typedef struct
{int x;//子弹坐标xint y;//子弹坐标yint v;//子弹速度int Size;//子弹大小int Colr;//子弹颜色
}ZiDan;
CDC *pDC;//定义pDC指向CDC类对象的指针DiJi m_JX[100];//矩形敌机
DiJi m_SJX[100];//三角形敌机
DiJi m_YX[100];//圆形敌机
int m_nJX;//矩形敌机数
int m_nSJX;//三角形敌机数
int m_nYX;//圆形敌机数ZiDan m_ZD[100];//子弹
int m_nZD;//子弹数int m_r;//坦克圆半径
int m_x;//坦克坐标x
int m_y;//坦克坐标y
int m_L1,m_L2;//坦克长
int m_LPT;//坦克炮筒长
int m_Dire;//坦克方向
int m_V;//坦克移动速度int m_ZongFen;//总分
int m_CiShu;//次数

4.变量初始化及画图函数

在构造函数中对变量进行初始化,并且新建画图成员函数,编写代码,调用画敌机函数,画子弹函数和画坦克函数,添加提示信息等。

在类中新建成员函数

构造函数中变量初始化

画图函数中调用其他函数进行绘图

5.敌机的实现

通过分析可知,敌机主要有4个函数,创造敌机函数,画敌机函数,移动敌机函数和消除敌机函数。

5.1创造敌机函数

新建CreateDiJi()成员函数,并添加如下代码,根据随机数选择创造相应类型的敌机,设置敌机的各项参数的值,敌机总数加1。

int sjs;//随机数
sjs = rand()%3;//对3求余,即0,1,2
switch(sjs)
{case 0:m_JX[m_nJX].x = rand()%700 + 50;m_JX[m_nJX].y = 0;m_JX[m_nJX].v = rand()%50 + 10;m_JX[m_nJX].Size = rand()%20 + 10;m_JX[m_nJX].FS = m_JX[m_nJX].v + 100/m_JX[m_nJX].Size;m_nJX++;break;case 1:m_SJX[m_nSJX].x = rand()%700 + 50;m_SJX[m_nSJX].y = 0;m_SJX[m_nSJX].v = rand()%30 + 10;m_SJX[m_nSJX].Size = rand()%60 + 30;m_SJX[m_nSJX].FS = m_SJX[m_nSJX].v + 300/m_SJX[m_nSJX].Size;m_nSJX++;break;case 2:m_YX[m_nYX].x = rand()%700 + 50;m_YX[m_nYX].y = 0;m_YX[m_nYX].v = rand()%40 + 10;m_YX[m_nYX].Size = rand()%40 + 20;m_YX[m_nYX].FS = m_YX[m_nYX].v + 200/m_YX[m_nYX].Size;m_nYX++;break;
}

5.2画敌机函数

新建DrawDiJi()成员函数,并添加如下代码,分别画不同类型的敌机,此处注意画三角形敌机时使用了三角函数需将math.h包括进来,即在开头添加#include "math.h"代码,并且宏定义PI,即在开头添加#define PI 3.1415926代码。

int i;
int x,y,r;
for(i=0;i<m_nJX;i++)
{x = m_JX[i].x;y = m_JX[i].y;r = m_JX[i].Size/2;pDC->Rectangle(x,y,x + r,y + r);
}
for(i=0;i<m_nSJX;i++)
{x = m_SJX[i].x;y = m_SJX[i].y;r = m_SJX[i].Size/2;pDC->MoveTo(x,y);x -= r;y += r*2*cos(PI/6);pDC->LineTo(x,y);x += 2*r;pDC->LineTo(x,y);x = m_SJX[i].x;y = m_SJX[i].y;pDC->LineTo(x,y);
}
for(i=0;i<m_nYX;i++)
{x = m_YX[i].x;y = m_YX[i].y;r = m_YX[i].Size/2;pDC->Ellipse(x - r,y - r,x + r,y + r);
}

5.3移动敌机函数

新建MoveDiJi()成员函数,并添加如下代码,根据不同类型敌机的速度改变敌机的y坐标,并设定边界,大于该值时便消失。

int i;
for(i=0;i<m_nJX;i++)
{m_JX[i].y += m_JX[i].v * 0.1;if(m_JX[i].y>750)DeleteDiJi(0,i);
}
for(i=0;i<m_nSJX;i++)
{m_SJX[i].y += m_SJX[i].v * 0.3;if(m_SJX[i].y>750)DeleteDiJi(1,i);
}
for(i=0;i<m_nYX;i++)
{m_YX[i].y += m_YX[i].v * 0.2;if(m_YX[i].y>750)DeleteDiJi(2,i);
}

5.4消除敌机函数

新建DeleteDiJi(int xz,int n)成员函数,并添加如下代码,根据变量xz选择不同类型敌机,并使所要删除的第n个敌机变为最后一个敌机就行,敌机总数减1。

switch(xz)
{case 0:m_JX[n] = m_JX[m_nJX-1];m_nJX--;break;case 1:m_SJX[n] = m_SJX[m_nSJX-1];m_nSJX--;break;case 2:m_YX[n] = m_YX[m_nYX-1];m_nYX--;break;
}

6.子弹的实现

通过分析可知,子弹和敌机类似,主要有4个函数,创造子弹函数,画子弹函数,移动子弹函数和消除子弹函数。

6.1创造子弹函数

新建CreateZiDan()成员函数,并添加如下代码,创造子弹,设置子弹的各项参数的值,子弹总数加1。

m_ZD[m_nZD].x = m_x;
m_ZD[m_nZD].v = rand()%50 + 25;
m_ZD[m_nZD].Size = rand()%20 + 10;
m_ZD[m_nZD].y = m_y - m_r*sqrt(3)/2 - m_LPT - m_ZD[m_nZD].Size/2;
m_ZD[m_nZD].Colr = RGB(120,160,200);
m_nZD++;

6.2画子弹函数

新建DrawZiDan()成员函数,并添加如下代码,画圆形子弹,并使用画刷填充子弹颜色。

int i;
int x,y,r;
for(i=0;i<m_nZD;i++)
{x = m_ZD[i].x;y = m_ZD[i].y;r = m_ZD[i].Size/2;CBrush brush;brush.CreateSolidBrush(m_ZD[i].Colr);pDC->SelectObject(&brush);pDC->BeginPath();pDC->Ellipse(x - r,y - r,x + r,y + r);pDC->EndPath();pDC->FillPath();
}

6.3移动子弹函数

新建MoveZiDan()成员函数,并添加如下代码,根据子弹的速度改变子弹的y坐标,并设定边界,小于该值便消除子弹。

int i;
for(i=0;i<m_nZD;i++)
{m_ZD[i].y -= m_ZD[i].v * 0.2;if(m_ZD[i].y < 75)DeleteZiDan(i);
}

6.4消除子弹函数

新建DeleteZiDan(int n)成员函数,并添加如下代码,根据变量n,删除第n个子弹,并使所要删除的第n个子弹变为最后一个子弹就行,子弹总数减1。

m_ZD[n] = m_ZD[m_nZD-1];
m_nZD--;

7.坦克的实现

通过分析可知,坦克主要有3个函数,画坦克函数,移动坦克函数,改变方向函数。

7.1画坦克函数

新建DrawTanKe()成员函数,并添加如下代码,画坦克。

int x1,x2,y1,y2,z1,z2;
x1 = m_L1/2;
x2 = m_L2/2;
y1 = 2*m_r;
y2 = 3*m_r;
pDC->Rectangle(m_x - x2,m_y - y2,m_x + x2,m_y + y2);
pDC->Rectangle(m_x - x1,m_y - y1,m_x + x1,m_y + y1);
pDC->Ellipse(m_x - m_r,m_y - m_r,m_x + m_r,m_y + m_r);
z1 = m_r/2;
z2 = m_r*sqrt(3)/2;
pDC->MoveTo(m_x + z1,m_y - z2);
pDC->LineTo(m_x + z1,m_y - z2 - m_LPT);
pDC->LineTo(m_x - z1,m_y - z2 - m_LPT);
pDC->LineTo(m_x - z1,m_y - z2);

7.2移动坦克函数

新建MoveTanKe()成员函数,并添加如下代码,根据不同的移动方向和移动速度来改变坦克的x和y坐标来实现移动坦克。

if(m_Dire == 1) m_x -= m_V;
if(m_Dire == 2) m_y -= m_V;
if(m_Dire == 3) m_x += m_V;
if(m_Dire == 4) m_y += m_V;

7.3改变方向函数

新建ChangeDire(int n)成员函数,并添加如下代码,根据变量n来识别按下的键盘是什么,从而通过键盘的上下左右键改变坦克的移动方向。

switch(n)
{case 37:m_Dire = 1;//向左break;case 38:m_Dire = 2;//向上break;case 39:m_Dire = 3;//向右break;case 40:m_Dire = 4;//向下break;
}

8.碰撞的实现

碰撞即子弹击中敌机和敌机击中坦克两部分,故可以使用2个函数实现,碰撞敌机子弹函数和碰撞敌机坦克函数。

8.1碰撞敌机子弹函数

新建PengZhuangDiJiZiDan()成员函数,并添加如下代码,外层循环是子弹,内层循环是敌机,根据不同类型的敌机 ,分别计算敌机和子弹之间的距离,并判断该距离若小于两者半径之和时就视为击中,因此总分就增加该敌机的分数,且消除该敌机和该子弹,同时break此次循环,再判断j是否小于该敌机数,若小于则continue继续循环判断。

int i,j;
int d;
for(i=0;i<m_nZD;i++)
{   for(j=0;j<m_nJX;j++){d = sqrt((m_ZD[i].x - m_JX[j].x)*(m_ZD[i].x - m_JX[j].x)+(m_ZD[i].y - m_JX[j].y)*(m_ZD[i].y - m_JX[j].y));if(d<m_ZD[i].Size/2 + m_JX[j].Size/2){m_ZongFen += m_JX[j].FS;DeleteDiJi(0,j);DeleteZiDan(i);break;}}if(j<m_nJX)continue;for(j=0;j<m_nSJX;j++){d = sqrt((m_ZD[i].x - m_SJX[j].x)*(m_ZD[i].x - m_SJX[j].x)+(m_ZD[i].y - m_SJX[j].y)*(m_ZD[i].y - m_SJX[j].y));if(d<m_ZD[i].Size/2 + m_SJX[j].Size/2){m_ZongFen += m_SJX[j].FS;DeleteDiJi(1,j);DeleteZiDan(i);break;}}if(j<m_nSJX)continue;for(j=0;j<m_nYX;j++){d = sqrt((m_ZD[i].x - m_YX[j].x)*(m_ZD[i].x - m_YX[j].x)+(m_ZD[i].y - m_YX[j].y)*(m_ZD[i].y - m_YX[j].y));if(d<m_ZD[i].Size/2 + m_YX[j].Size/2){m_ZongFen += m_YX[j].FS;DeleteDiJi(2,j);DeleteZiDan(i);break;}}if(j<m_nYX)continue;
}

8.2碰撞敌机坦克函数

新建PengZhuangDiJiTanKe()成员函数,且该函数类型是int型,有一个返回值,返回值用于后面判断是否碰撞,并添加如下代码,循环是敌机,根据不同类型的敌机 ,分别计算敌机和坦克之间的距离,并判断该距离若小于两者半径与炮筒长之和时就视为击中,因此碰撞标志变为1,且消除该敌机,玩家游戏次数减1,返回碰撞标志。

int i,d;
int flag=0;
for(i=0;i<m_nJX;i++)
{d = sqrt((m_JX[i].x - m_x)*(m_JX[i].x - m_x)+(m_JX[i].y - m_y)*(m_JX[i].y - m_y));if(d<m_JX[i].Size/2+m_r*sqrt(3)/2+m_LPT){flag=1;DeleteDiJi(0,i);m_CiShu--;return flag;}
}
for(i=0;i<m_nSJX;i++)
{d = sqrt((m_SJX[i].x - m_x)*(m_SJX[i].x - m_x)+(m_SJX[i].y - m_y)*(m_SJX[i].y - m_y));if(d<m_SJX[i].Size/2+m_r*sqrt(3)/2+m_LPT){    flag=1;DeleteDiJi(1,i);m_CiShu--;return flag;}
}
for(i=0;i<m_nYX;i++)
{d = sqrt((m_YX[i].x - m_x)*(m_YX[i].x - m_x)+(m_YX[i].y - m_y)*(m_YX[i].y - m_y));if(d<m_YX[i].Size/2+m_r*sqrt(3)/2+m_LPT){ flag=1;DeleteDiJi(2,i);m_CiShu--;return flag;}
}

9.视图类调用及新建菜单项目

9.1新建菜单项目

新建菜单栏,在这里设置2个功能栏,开始游戏和暂停游戏,并建立视图类向导。

9.2视图类调用

先在刚刚添加的2个消息响应函数中添加代码,在开始消息响应函数中设置2个定时器,一个时间间隔为1000毫秒即1秒,另一个时间间隔为100毫秒,在暂停消息响应函数中停止2个时钟。

然后添加时钟控制函数和键盘控制函数。

在添加代码之前,因要调用坦克大战类中的函数,故需要在视图类的头文件中定义一个对象,并包括坦克大战类的头文件,且在视图类的.cpp文件中也应包括坦克大战类的头文件。

最后在OnDraw()中调用坦克大战类的画图函数,在OnKeyDown()中调用坦克大战类的改变方向函数,在OnTimer()中调用坦克大战类的创造函数,移动函数,碰撞函数,并且根据时钟号的不同设置调用时间间隔不同。创造函数每隔1秒调用一次,移动函数和碰撞函数每隔100毫秒调用一次。并且对于玩家游戏次数进行判断,若为0,则终止游戏。若不为0,则提示后继续游戏。

在OnDraw()中添加代码

tw.Draw(pDC);

在OnKeyDown()中添加代码

tw.ChangeDire(nChar);

在OnTimer()中添加代码

if(nIDEvent == 1)
{tw.CreateDiJi();tw.CreateZiDan();Invalidate(true);
}
if(nIDEvent == 2)
{tw.MoveDiJi();tw.MoveZiDan();tw.MoveTanKe();tw.PengZhuangDiJiZiDan();if(tw.m_CiShu != 0){if(tw.PengZhuangDiJiTanKe()==1){CString str;str.Format("还剩%d条命!",tw.m_CiShu);AfxMessageBox(str);SetTimer(1,1000,NULL);SetTimer(2,100,NULL);}}else{KillTimer(1);KillTimer(2);AfxMessageBox("Game Over!");}Invalidate(true);
}

为消除屏幕的闪烁问题,可用双缓存技术解决。先添加擦除背景函数并将返回值为true,然后将OnDraw()中代码变成如下代码。

10.游戏效果展示

总结

这个基于MFC的坦克大战小游戏,可以说将面向对象思想和程序模块化思想体现的比较好。通过练习,对于这两种思想的理解会更进一步。

源码下载地址,仅供参考。

https://download.csdn.net/download/Zgh12138/12625604

MFC小游戏之坦克大战相关推荐

  1. 微信小游戏制作坦克大战(四)添加敌方坦克,敌方坦克可以随机移动

    微信小游戏制作坦克大战(四)添加敌方坦克,敌方坦克可以随机移动 首先导入敌方坦克素材 重命名为敌方坦克1 敌方坦克也移动到屏幕外面,后面使用克隆体来显示. 我们给敌方坦克添加事件 好的,现在敌方坦克已 ...

  2. 微信小游戏制作坦克大战(六)碰撞检测,主角坦克碰到敌方坦克、炮弹爆炸

    微信小游戏制作坦克大战(六)碰撞检测,主角坦克碰到敌方坦克.炮弹爆炸 导入坦克爆炸效果的图片和声音素材 给主角坦克添加事件 给爆炸动画添加事件 当主角坦克碰到敌方坦克或者炮弹时显示爆炸效果 下一篇文章 ...

  3. 微信小游戏制作坦克大战(五)敌方坦克可以发射炮弹

    微信小游戏制作坦克大战(五)敌方坦克可以发射炮弹 在资源管理器中复制炮弹,重命名为敌人坦克的炮弹. 修改敌方坦克的积木 给敌方坦克炮弹添加事件 现在,敌方坦克已经可以自动发射炮弹啦. 下一篇文章:微信 ...

  4. 使用jquery—Canvas实现html5小游戏——《坦克大战》

    目录 1.项目背景 2.项目展示 3.设计思路 3.1.坦克移动 3.2.坦克开火 3.3.击中坦克 4.实现代码 5.总结 1.项目背景 2021年春节期间在家无聊,正好又学过一些前端的知识,因此就 ...

  5. 微信小游戏制作坦克大战(九)切换场景,游戏重新开始

    微信小游戏制作坦克大战(九)切换场景,游戏重新开始 新建一个游戏结束场景 主角坦克爆炸后切换到游戏结束场景 添加背景音乐 好了,至此坦克大战小游戏基本做好,小伙伴们可以继续完善哈. 体验地址:

  6. 微信小游戏制作坦克大战(八)统计得分

    微信小游戏制作坦克大战(八)统计得分 导入数字图片素材 新建得分变量 给数字添加事件 敌方坦克发生爆炸时,数字增加1 实现效果 下一篇文章:微信小游戏制作坦克大战(九)切换场景,游戏重新开始

  7. 微信小游戏制作坦克大战(七)碰撞检测,敌方坦克碰到主角坦克炮弹爆炸

    微信小游戏制作坦克大战(七)碰撞检测,敌方坦克碰到主角坦克炮弹爆炸 导入发生炮弹的音效素材 主角坦克发射炮弹或者敌方坦克发射炮弹时播放音效 修改敌方坦克积木 4.效果: 敌方坦克碰到主角坦克炮弹爆炸 ...

  8. python小游戏经典坦克大战-实验设计

    一. 游戏流程概述 游戏基本规则: 按上下左右键移动我方坦克,按空格键进行发射子弹,击中坦克,坦克爆炸消失.若我方坦克被子弹击中或撞上,我方坦克死亡按ESC键可以重生. 敌方坦克功能:白色敌方坦克为一 ...

  9. cocos2d-xna 写的一个小游戏demo坦克大战

    最近看到网上介绍cocos2d的资料很多,看了看cocos2d也支持wp7,下载了个 Cocos2d-XNA 安装包,写个小例子玩玩,熟悉下cocos2d 程序很简单,就一个入门级的小游戏,写完后放手 ...

  10. Unity开发笔记(五)—— 制作第四个小游戏《坦克大战》

    目录 使用VS传统方法制作 使用Unity制作 使用VS传统方法制作 写在前面的话 C#可以干什么? 桌面应用开发(用的少,现在市面上的桌面应用大部分是C++开发的) Unity游戏开发 Web开发( ...

最新文章

  1. 不用回调方法捕获数据包
  2. Python编写简易木马程序
  3. android 7 创建文件夹,Android 在 res/layout 文件夹 下创建一个 子文件夹实例
  4. 自定义注解 相关知识汇总(转)
  5. EditPlus 使用技巧集萃(转)
  6. B站在港交所暂停交易
  7. vue仿微博评论回复_Vue之 3.0升级
  8. 接口(interface)有什么优点,为什么要用接口
  9. numpy实用技巧(一)
  10. bzoj 1078 [SCOI2008]斜堆 —— 斜堆
  11. matlab中构建Cuk变换器,CUK变换器的SIMULINK仿真与应用.pdf
  12. 2级c语言题库及答案,计算机二级C语言上机题库含答案解析
  13. redis命令之哈希表类型lpush命令用法详情
  14. 我的个人学习的小总结
  15. redis之瘦小精干的位图 (一)
  16. 【Linux】gcc编译器下载与手动安装
  17. Vue无缝滚动轮播插件vue-seamless-scroll
  18. python 爬虫 微博 github_GitHub - bubblesran/weiboSpider: 新浪微博爬虫,用python爬取新浪微博数据...
  19. python数据函数定义的规则是什么_Python自定义函数基础概念
  20. 【机器学习】懒惰学习

热门文章

  1. mac虚拟机改显存_虚拟机mac怎么增大显存
  2. 7-32 哥尼斯堡的“七桥问题”
  3. OSPF多区域中必须有area0。非area0区域要与area0相连才能实现传播域间路由信息
  4. fastjson解析json文本
  5. 横沥东莞注塑工艺需要考虑的7个因素
  6. 设计模式学习——代理模式(proxy)
  7. Linux下安装小企鹅输入法
  8. 如何进行数据安全管理体系建设?
  9. easyui filebox+ajaxfileupload实现异步上传
  10. 下载blob地址或m3u8格式视频方法以及常见问题解决