2013年10月1日 星期二

Android坦克大战游戏设计解析五

http://www.imobilebbs.com/wordpress/archives/743

Android坦克大战游戏设计解析五

本篇介绍坦克大战游戏场景类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中填入石块,由于宝贝有时效性,到了一定时间后将“家”变回普通砖块做成。