QT FC坦克大战
QT设计的类似FC坦克大战的程序。暂时只完成了单人模式,双人模式可以后续自行添加。
源码以及图片音频资源下载地址:上传暂时还在审核中...后续更新
目录
程序描述
关卡为26*26的方格,背景为黑色。
关卡内,场景对象包括环境:砖块,铁块,草,水,大本营;角色:我方坦克,敌方坦克;
移动:我方坦克,可以通过WASD四个按键,实现方向控制,敌方坦克,会随机移动。坦克遇到砖块,铁块与水,会无法继续前行,遇到草会隐藏在草丛下方。敌方坦克的行为规则:如果能继续前进,则坦克以0.7的概率前进,0.3的概率向其他三个方向转向。如果被挡住,四个方向各以0.25的概率转向。任何时刻,坦克都以0.3的概率向当前方向发射子弹。
发射子弹:我方坦克通过按鼠标左键,发射子弹,敌方坦克,随机发射子弹。子弹以恒定速度前行。
子弹击中砖块,会令砖块消失,同时子弹消失。击中铁块,子弹消失,铁块不变。击中水与草,会穿过。子弹碰到四周边界会消失。子弹击中对方坦克,会令对方坦克消失,并显示0.5秒钟爆炸特效。
子弹击中大本营,会判定失败。
关卡开始后,会随机在最顶行刷新20只坦克,刷新时,会显示0.5秒钟出生特效,我方坦克出生时会显示无敌特效。
敌方坦克有三种,分别为被子弹击中一次,两次,三次击杀。我方坦克被击中三次后死亡。敌方坦克彼此击中不会死亡。
当对方二十辆坦克都被击杀后,我方胜利。当我方被击杀三次,或者大本营被摧毁后,敌方胜利。
实现多关卡,主要为原任天堂游戏地图。
添加部分音效,为原游戏音效。
实现动态显示剩余坦克数、关卡数、我方坦克生命值,与原任天堂游戏相似。
实现游戏结束画面,与原任天堂游戏相似。
程序运行效果如下(GIF):
程序基本思路
程序的基本框架
对程序进行板块划分,划分为地图、坦克类、我方坦克类(继承坦克类、调用子弹类)、敌方坦克类(继承坦克类、调用子弹类)、子弹类以及两个窗口(菜单窗口和游戏窗口)。
地图:使用26*26的二维int数组(地图块种类:nothing 0, wall 1, steel 2, sand 3, water 4, grass 5, boss 6,boss boom 7)。地图由13*13个30*30像素的大地图块组成,每个大地图块由四个15*15像素的小地图块组成。
计时器(timer)每100ms刷新一次。
坦克类:
坦克为30*30像素的图片;
成员变量:横纵坐标(x,y)、坦克方向(dir)、坦克速度(speed)、生命值(hp)、坦克等级(level)、坦克是否存活(isAlive)、坦克是否隐藏(mask)、地图数组(map);
坦克是否隐藏(mask)用于判断坦克碰撞到草地(grass)后,是否隐藏;
生命值(hp)用于判断坦克剩余受击次数,位0时,坦克爆炸;
坦克等级主要用于判断敌方坦克的类型,被子弹击中一次,两次,三次后击杀爆炸。
子弹类:
成员变量:横纵坐标(x,y)、子弹数量(count)、子弹方向(dir)、子弹速度(speed)、子弹碰撞类型(collision)、子弹是否存活(isAlive);
子弹碰撞类型用于表示子弹击中的目标类型(地图块、子弹、坦克、边界、营地五种情况),方便判断被击中目标的下一步绘制方法。
我方坦克类(继承坦克类、调用子弹类):
子弹类类对象(bullet),自定义子弹类vector容器(bullet_vector);
成员函数:void fire() 我方坦克的发射子弹函数;
成员变量:计时器(timer)、判断上下左右(up、down、left、right);
槽函数:void move() 我方坦克移动的槽函数。
敌方坦克类(继承坦克类、调用子弹类):
成员函数:void run() 敌方坦克的移动函数;
子弹类类对象(en_bullet),自定义子弹类vector容器(en_bullet_vector)。
菜单界面:
槽函数:void on_pushButton_clicked();
void on_L_Reco_clicked();
void on_EXIT_clicked();
分别对应开始游戏、帮助和退出游戏。
我方坦克(JPG)
敌方坦克(JPG)
level1 level2 level3
地图块(JPG)
grass wall ice iron river
子弹(JPG)
子弹爆炸(JPG)
坦克爆炸(JPG)
游戏音频(WAV)
主要思路
游戏开始时播放对应音频(.wav);
首先根据地图数组进行绘制地图,然后通过我方坦克类中的定时器(timer)进行我方子弹和敌方子弹、我方子弹和敌方坦克、敌方坦克和敌方坦克、敌方子弹和我方子弹、敌方子弹和敌方子弹的碰撞检测,制造敌方坦克,营地击中检测、地图更新;
通过对我方坦克的移动控制(即W、S、A、D、鼠标左键的点击),实现我方坦克的移动和发射子弹。当碰撞到草地(grass)时,停止绘制我方坦克,但横纵坐标依然更新,直到坦克完全移出草地(grass)。当我方坦克被击中三次后,爆炸,游戏结束;
子弹射出时,压入到对应的vector中,包括子弹的速度、方向、横纵坐标等信息。子弹射出后,根据一定规则运动。当子弹发生碰撞时,通过判断碰撞的对象,从而改变子弹碰撞类型(collision)的值,根据不同的碰撞类型值在更新绘制时实现对子弹、坦克和地图块的更新,同时该子弹从vector中清除。如果子弹所属的坦克没有存活,该子弹从vector中清除;
首先创建3个敌方坦克到地图中,同时压入到自定义敌方坦克类vector容器中,且开始移动。当vector中的坦克数小于5时,在三个固定出生点随机创造一个敌方坦克,同时创建子弹压入对应vector中,以此循环,直至地图中坦克数等于5。敌方坦克的等级随机刷新。敌方坦克根据一定的规则移动和发射子弹。当碰撞到草地(grass)时,停止绘制敌方坦克,但横纵坐标依然更新,直到坦克完全移出草地(grass)。
绘制时根据地图数组依次绘制地图块,根据自定义敌方坦克类vector容器依次绘制敌方坦克,根据自定义子弹类依次绘制子弹,根据我方坦克横纵坐标绘制我方坦克;
游戏结束时绘制游戏结束画面并播放对应的音频(.wav)。
部分算法
我方坦克移动控制
通过四个bool型数据,分别代表上下左右(up、down、left、right)。如果某一数据为true,则表示向该方向移动。通过对键盘事件的响应,即mouseEvent的重写,来改变这四个bool类型的值。 每当计时器(timer)运行一次,就对这四个数据进行判断。当只有某一个数据为true时,我方坦克就根据在该方向上的移动规则移动。 向上的移动规则: 首先判断是否出现上移越界的情况,即纵坐标大于5。如果有,则坦克不移动;如果没有,则继续判断坦克与地图块的碰撞。 坦克与地图块的碰撞分为以下情况:地图为空、地图为草地、地图为沙地等。 地图为空:正常前进; 地图为草地:坦克隐藏,继续前进; 地图为沙地:加速前进; 其余情况:不前进; 对于具体的碰撞检测,原理是将坦克的横纵坐标转换为地图数组中的元素,再判断该元素的各个方向的地图块种类。有以四下种情况(以图示说明): 其他方向的规则类比向上的规则; 当检测到为草地时,是否隐藏(mask)为true,否则为false; |
敌方坦克移动,子弹发射
首先判断坦克是否存活(isAlive); 再通过swithc判断坦克的方向(dir): Case 0: If(坦克没有上移越界) 根据算法1中坦克与地图块的碰撞检测原理,判断坦克是否移动; If 移动 随机生成一个大于0小于10的数,根据书的大小,坦克有0.3的概率转向,0.7的概率直行; Else 随机转向; Case 1:原理同case 0; Case 2:原理同case 0; Case 3:原理同case 0; |
子弹移动
子弹为6*6像素大小的图片; 判断子弹存活时: Switch(子弹方向(dir)) Case 0: 根据算法1中坦克与地图块的碰撞检测原理,判断子弹是否移动; 碰撞类型有: 空白、草地、沙地、河流:正常移动; 铁块、砖块:停止移动,并返回对应的碰撞类型值(collision),同时子弹移除; Case 1:原理同case 0; Case 2:原理同case 0; Case 3:原理同case 0;
如果边界越界,返回对应的碰撞类型值(collision),同时子弹移除; |
子弹发射
坦克向各个方向发射子弹示意图(以向上为例): 子弹发射时,子弹的方向立即确定,且不被改变,即为发射时坦克的方向; |
我方子弹与敌方坦克的碰撞检测
槽函数,当计时器更新时调用; If(我方坦克存活){ For循环,遍历每一个我方坦克子弹(最多为2个) 对每一个我方坦克发射的子弹: For循环,遍历每一个敌方坦克 If(敌方坦克存活) 根据一定的规则,判断我方子弹是否击中敌方坦克,规则如下图 } 子弹击中目标后,目标和子弹移除; |
敌方坦克与敌方坦克的碰撞检测
碰撞原理如图: 敌方坦克1向上与敌方坦克2向下碰撞后:坦克1、2均反向; 敌方坦克1向上与敌方坦克2向左或右碰撞后:坦克1在上则坦克2反向,反之,坦克1反向; 敌方坦克1向下与敌方坦克2向左或右碰撞后:坦克1在上则坦克1反向,反之,坦克2反向; |
界面设计
程序窗口基本框架
菜单界面
去掉标题栏,设置三个按钮,分别对应开始游戏、帮助、退出游戏,通过QPalette设置背景图片。
游戏界面:
去掉标题栏;
将游戏界面分为两部分,一个为游戏主体,一个为游戏信息实时显示;
游戏主题设置背景图(纯黑色);
游戏信息实时显示部分以灰色为背景图,主要分为敌方坦克数量、关卡数、我方坦克生命值的显示。敌方坦克数以2*10的排列方式显示,每减少一个敌方坦克,对应减少一个敌方坦克标志。关卡数以“旗帜”图案和数字的方式显示,每前进一关,数字加一。我方坦克数量以我方坦克标志和数字的方式显示,该数字随坦克生命值(hp)的变化为变化。
实际运行效果
营地被击中:
通过草地: