基于C++实现的经典坦克大战游戏

Feelme

发布日期: 2018-11-14 12:09:16 浏览量: 905
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

1 题目描述

这战车大战就是指红白机的战车大战,操纵战车,将敌人通通轰掉,完成这个关卡。

小时后完红白机时,不能输人金手指,没办法自由控制游戏,现在刚好有这个OOP专题机会,我们就仿制一个战车大战,自己可以完全控制程序码,做到比输人金手指更完整的控制。

程序使用 DEV-C 编译器进行开发。

2 系统架构和分析

一刚开始,我们思考这游戏的雏型该怎么定义,我们认为,需要有:战车、子弹、地图(map)、实体(body)。

有实体(body)的原因是因为,画在winBGI的图形就像影子一样,那只是显示给我们看的,计算机根本不知道子弹有没有打到砖块,有没有打到战车,所以就将 winBGI窗口416x416个像素,都用数组body[416][416],每个像素目前是谁占据着,都会纪录在这数组里,之后计算机要判断这块区域中有没有障碍,子弹有没有打到砖块,哪台战车被打到,都可以直接从数组判断。

虽然已经有body[416][416]这个数组了,另外还有map[26][26]这数组,因为每种地形(砖块、海…)都是16x16的方块,所以416x416像素,可以分成 26x26 个数组,map[26][26]这数组主要有两个作用:一个是画图时,就读这个数组,把相对应的地形都印在winBGI,另一个是可以直接利用档案IO,从外部编辑地图 (.txt),所以不用再手动排地图。

有一个函数setactaulbarrier(int y, int x, int type),将 body[416]\ [416]与map[26] [26]联结起来。以 16x16 像素为一单位,将map[26][26]上纪录的编号(代表不同地形),映射到body[416][416]。

另一函数tankbarrier(item tank),将战车也纪录到body[416][416],战车的存在对别台战车来说,跟其他地形一样,也是一种障碍,有障碍的话就无法前进;这样才不会有两个战车的位置重迭,而且子弹才能判断他打到的是哪一台战车。

战车编号如果是”0”的话,就代表死亡,在body[416][416]上写为”0”,就不会对其他战车造成障碍。

下面有一个例子,说明数组map[26][26]、数组body[416][416]与WinBGI上的对应关系。

body[416][416]上的数字代表:

  • 1:地形,砖块

  • 2:地形,草棚

  • 3:地形,钢墙

  • 4:地形,海洋

  • 50-70:代表各台战车

我们定义了一个struct item这是给游戏中的战车用的,纪录读图的路径、战车目前的坐标、方向、战车的编号、有几条命、子弹的速度、属于哪一队,有什么特殊效果(有防护罩时,或是被打到会喷道具)。

另一个struct是给子弹用的,纪录子弹坐标、方向、是否在发射状态。

上面是程序主要部分,有两个主要的函数,一个叫作animation(),是负责画图的函数,这函数的作用就是控制图案的输出。

另一个叫作itemctrl(),整个游戏的规则都是由这控制的,专门控制图案的位置,子弹的位置、速度,战车的位置、速度,砖块是否被打到,被打到后会怎样,都是这个函数控制的。

最后一个重要的部分是敌方如何追踪玩家战车,我们把每个阶段想到的方法都留下来,总共有13个,编号越后面,考虑的条件会越多,也会聪明一些。

追踪的方法是这样的:

假设往上下左右四个方向各走一步,看哪个方向离目标最近,就选哪个方向。如果算出来是下最近,但是前方刚好有砖块过不去,该怎么办呢?是砖块的话,就直接打穿前面的砖块往前走,如果是钢墙的话,这招就行不通了,程序会纪录战车上一次的位置,如果上次位置与这次位置一样,表示他无法打穿这个障碍物,所以就山不转路转,决定绕路!

程序会纪录 上下左右 哪个方向是不能走的,像上面那种情况,它的”下”是不能走的,所以它就会选择往左或右”一直走”,直到侦测到原本不能走的”下”,现在可以走了,这样就绕过障碍物了。

3 执行结果

程序一开始,有说明控制方式,选单有两个选项:

  • 1是进人游戏

  • 2是编辑地图

  • 控制方式:箭头键

  • Z:发射普通子弹

  • X:发射后,还能控制方向的子弹

  • C:在战车周围旋转的子弹

  • V:会自动追踪敌人的子弹

进人编辑地图,点击右边的选项,可以用鼠标编辑,利用档案IO使两个程序能编辑同一张地图。

进人游戏,把敌方战车全杀光就算赢;生命值耗尽就会输。

这些是全部的道具(期末demo后才加上去的)

4 问题及解决

4.1 遇到的问题一

第一个遇到的问题是,战车常常被砖块卡住,发现原因是这样的:因为战车是由四个顶点的坐标侦测是否前方有障碍物。

像上图这种情况,现在战车方向是”上”,所以上方两个顶点(绿色),会在数组body[416][416]侦测到前方已经有砖块了,所以不能再往前了。

不过像这种情况,战车想往上走,明明前方没障碍物,但是右上方那点已经侦测到砖块,所以战车就会无法前进,感觉像是被砖块黏住。

4.2 解决方法

知道了原因,我们的解决方法就是,把四个顶点的距离改成不再都是26像素。

这样一来,因为侦测顶点的距离从26像素加大到30像素,当战车往右走时,右边有障碍物,它会较早就被障碍物挡住,此时,方向转”上”的话,右上方的点就不会侦测到障碍物,就能顺利地前进了。缺点是要牺牲左右方向的自由度,不能过分接近障碍物。

4.3 遇到的问题二

另外一个较大的问题是,有时会存取超出范围的数组,导致程序崩溃。

因为战车每移动一次,就会在数组body[416][416],在相对应的坐标写入战车的编号,纪录位置,战车的速度是3像素,假如目前战车的坐标是(414, 414),现在它要往右走,照理说坐标要变为(417, 414)了,但是body[417][414]已经超出数组定义的范围了,所以程序就崩溃了。

4.3 遇到的问题三

还有另一个类似的问题,子弹打到边界的砖块,因为没考虑周全,运算出来是map[26][10]这个砖块必须被消除,其实index 26已经超过原本定义的大小了 (char map[26][26], index:0-25),但这时后程序反而不会崩溃,但是计算机会去存取 map[0][10]的数据,所以就造成了:明明打到的是右边,却是左边的砖块被消除掉,难道map[26][10]==map[0][10]?这我们也摸不清。

4.4 解决方法

为了解决上述超出边界的问题,就是把边界变成不是边界,数组body[416][416]加大成body[448][448], map[26][26]变成map[28][28],然后我们使用 body[16~431][16~431]与map[1~26][1~26]当作战车可以出现的范围,所以就算偶而超出边界,也不会超出定义的数组大小,造成崩溃。

4.5 总结

写专题感觉很有趣,感觉就像是玩模拟市民、模拟城市一样,可以自己动手创造,做出任何自己想要的效果,虽然只是个小小的程序,别人眼中或许不怎样,但自己玩起来还是颇有成就感。

感觉我们太晚教到class了,对class的使用也不太熟悉,不然使用class的话程序应该可以写得更简洁明了。

有时遇到问题时,感觉跟数学很像,一直想就是想不通,怎样debug也找不出错,今天放弃后,明天换个心情重新看一次,竟然就看出问题在哪了。

我们专题题目太晚定下来了,改了两次最后才决定做坦克大战,如果早点决定,时间就可以充裕些了。

上传的附件 cloud_download 基于C++实现的经典坦克大战游戏.7z ( 1.61mb, 113次下载 )
error_outline 下载需要8点积分

发送私信

去奋斗,去追求,去发现,但不要放弃

11
文章数
11
评论数
最近文章
eject