如何用C语言去实现一款小游戏?相信很多初学C的同学,面对控制台输出的"Hello World"感到头疼,甚至觉得学习C语言并没有什么用。其实,C语言也可以方便的实现一个小游戏,下面来看看一个经典的游戏,坦克大战。
如下图所示,是采用C语言编写的字符版坦克大战游戏。其中,坦克分为玩家坦克一辆,和敌方坦克若干。使用电脑键盘控制玩家坦克,按下'W','S','A','D'分别为上、下、左、右移动,按下‘J’可以发射子弹。另外,还有墙壁,方便玩家躲避敌方的进攻。子弹击中坦克,会在原地爆炸,显示出一个爆炸的效果。编译器选用较多人熟悉的VC++6.0。
那么,设计这个游戏主要的思想是什么呢?其实就是图像之间的运算。两张图之间,也存在着加、减、或、与等运算。具体来讲,坦克大战游戏有一张背景图,可以用一个二维数组存储每个像素点的内容。我们定义这个内容是:有砖块为1,没砖块为0。而坦克本身也是一张移动的小图片。那么当一个小图片覆盖在背景图之上时,我们只需要查看在这个被覆盖的范围内,背景图里面的内容。如果存在这样一个坐标:在这个坐标上,小图片像素点内容为1,且背景图像素点内容也为1。那么可以认为小图片与背景图发生了重叠。这样的运算,就是与运算,也就是拿小图片里面的每个像素单元和背景图里面对应的像素单元进行逻辑与。运算的结果表示了是否发生重叠。如果任何一个坐标,像素点相与的结果不为0,那就是有重叠。在这个游戏里面,有重叠可以视为发生了“碰撞”。
我们知道了图像之间运算的概念,就可以定义很多图层,比如背景图,敌方坦克图、我方坦克图,敌方子弹图、我方子弹图...等等。我方坦克的移动都将表现在我方坦克图上,其他的同理。这样一来,游戏就很好做了。因为可以非常方便的知道,坦克、子弹等物体的运动情况。思考以下几个问题:
1,怎么知道我方坦克是否碰撞到砖块?拿我方坦克图和背景图进行与运算;
2,怎么知道敌方坦克是否被我方子弹击中?拿敌方坦克图和我方子弹图进行与运算;
...
思考以上问题之后,就能明白,坦克大战游戏的核心思想,其实就是图层之间的运算。其实不光坦克大战游戏,换个什么"飞机大战"游戏,也是一样的道理。
所以我们会定义很多图层:
char TankMap[X][Y] = {0};
char PlayerBulletMap[X][Y] = {0};
char EnemyBulletMap[X][Y] = {0};
char BackMap[X][Y] = {0};
char ArtMap[X][Y] = {0};
char AllMap[X][Y] = {0};
我们还会实现很多与图像相关的函数。比如图像写入,就是把Icon这样的小图像,写入到 GameMap大图像中。实际使用时,一般Icon是坦克,而GameMap是我方/敌方坦克图层。就好像贴图一样,把Icon粘贴到GameMap范围内的任意位置。
void WriteIcon(char GameMap[X][Y],char Icon[H_ICON][W_ICON],int x,int y)
还有碰撞检测。其实就是Icon和GameMap之间进行与运算。比如坦克小图标和背景图之间进行碰撞检测。
char OverLapCheck(char GameMap[X][Y],char Icon[H_ICON][W_ICON],int x,int y)
这里就不一一介绍了,因为后面会给出整个源代码。
我们还需要介绍的一个内容是,我们在程序中定义了多达6个图层,那么最终屏幕上显示什么呢?显然,所有的内容都是要被显示到屏幕上的。但是出现重叠怎么办?这个时候就要考虑一个优先级,即规定:两个图层在同一个位置有元素时,只显示哪个图层的。我们的做法是,把五个图层的内容进行或运算,结果保存到AllMap图层。所以,最终屏幕上显示的其实是AllMap图层的内容。
除此之外,还有一个小小的问题要考虑。我们设计的坦克大战是多人坦克大战,意味着敌方坦克会同时出现很多辆。那么这些坦克,需要用一个数组存储,然后循环挨个处理。在这个数组中,每个坦克都有一个标志位,代表它是活的,还是已经死亡。已经死亡的坦克将不能被显示,也不能发子弹和移动。这些死亡的坦克,会在敌方坦克数目较少时,被重新激活,以保持游戏难度。