本篇介绍坦克大战游戏场景类BattleField的设计思路。
BattleField 是Game API中TiledLayer的子类。TiledLayer实现了由小的图形(称为tile)拼接成大的背景,坦克大战游戏的背景是由砖块,石块,树林,水面,雪地等小的图片拼接而成。TiledLayer可以很容易的实现这种类型的背景,包括水面波汶的动态效果。
下面的图片是一个简单由多个小tile组成的游戏背景。
理论上TiledLayer可以实现无限大的背景。为简单起见坦克大战游戏中采用了半随机的方法来生成游戏背景,同时也提供了从文件读取游戏背景的方法,如果想完全复现FC的每一关,可以使用地图编辑器或是文本编辑器生成文件,然后从文件中读取背景。
这里给出一个关口的例子文件。
0000000000000 0202020202020 0202020202020 0202026202020 0202020202020 0000020200000 6022000002206 0000020200000 0202020202020 0202020202020 0202000002020 0000000000000
其中0代表空白,1代表雪地,2代表砖块,3代表树林,4,5代表水面,6代表石块。由于每个tile比较小,这里每个数据代表一个2X2的区块,下面代表实现从文件生成游戏背景
/** * Read the battle from an input stream. * @param is input stream stores the battle field information. */ private void readBattlefield(java.io.InputStream is) throws IOException { int c = -1; int x0 = (WIDTH_IN_TILES-NUMBER_IN_TILES)/2; int y0 = (HEIGHT_IN_TILES-NUMBER_IN_TILES)/2; int x=0,y=0; while ((c = is.read()) != -1 && y < NUMBER_IN_TILES) { switch (c) { case ' '://empty case '0': duplicateCell(x+x0, y+y0, 0);x+=2; break; case '1'://snow field duplicateCell(x+x0, y+y0,SNOW);x+=2; break; case '2'://brick wall duplicateCell(x+x0, y+y0, BRICK_WALL);x+=2; break; case '3'://forest duplicateCell(x+x0, y+y0, FOREST);x+=2; break; case '4': case '5'://water duplicateCell(x+x0, y+y0, -1 - ((x ^ y) & 1));x+=2; break; case '6': //Concrete wall duplicateCell(x+x0, y+y0, CONCRETE_WALL);x+=2; break; case '\n'://new line y+=2; x = 0; break; default: } } }
实现在游戏中采用了半随机的方法,这样游戏关卡可以有无限多,半随机是指一半的砖块是从HZK16(16点阵汉字库)读取一个汉字,用其点阵显示为砖块,其它雪地,树林等采用随机数随机分布在游戏场景中。前几关的汉字是“引路蜂软件”。
坦克大战游戏中还会随机出现一些增强法宝,比如定时器可以让敌方坦克停止运动,地雷可以使屏幕中敌方坦克全部炸毁。铁锹可以让“家”全部被石块包住从而使敌方子弹无法打穿。星星可以让已方坦克加速,同时发射的子弹数增加并增加打击能力(比如可以打穿石块甚至树林等等)。
所以BattleField中同时也定义了显示PowerUp(增强法宝),初始化敌方坦克位置(一般是从最上方的左,中,右依次出现)。另外还要判断某个位置坦克是否可能通过(有砖块,石头,水面不能通过),雪地要加速,其它地方可以通行。另外还要判断子弹是否击中墙壁(子弹击中墙壁后要爆炸等等)。
最后来看看它的tick()中主要做些什么
public void tick() { int tickState = (tickCount++ >> 3); // slow down x8 int tile = tickState % 2; setAnimatedTile(-1 - tile, waterFrames[tile][(tickState % 4) / 2]); if(concreteWallStartTime>0){ long tickTime=System.currentTimeMillis(); if(tickTime-concreteWallStartTime>concreteWallPeriod){ makeHomeBrickWall(); concreteWallStartTime=0; } } }
它主要显示水面的动态效果,如果当前需要显示石块做的家,则将相应的cell中填入石块,由于宝贝有时效性,到了一定时间后将“家”变回普通砖块做成。