Facebook Twitter LinkedIn E-mail
magnify
Home Posts tagged "手机游戏"

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

这是本系列最后一篇,最后就是将整个程序组成起来。坦克大战游戏中有六个用户界面:
音效设置
开始界面
选择关卡界面
游戏主界面
分数界面
游戏结束界面
按照Android程序一般设计方法,一般一个界面对应一个Activity。这样就需要设计6个Activity子类对实现各个界面。
在移植的过程,这里采用了一个简单的方法,采用一个Activity对就于 Java ME中的Midlet。
主Activity采用FrameLayout

<?xml version=”1.0″ encoding=”utf-8″?>
<FrameLayout xmlns:android=”http://schemas.android.com/apk/res/android
    android:id=”@+id/mainwindow”
    android:layout_width=”fill_parent”
    android:layout_height=”fill_parent”
    >
</FrameLayout>
FrameLayout 可以将它其中的其它View象扑克牌一样叠放在一起,这样将六个界面都放在主Activity的FrameLayout中,开始将它们都设置为不可见,需要显示某个界面时,设为可见并放在最前面,也就实现了多个用户界面。

public static void setCurrentScreen(View newScreen){
 currentScreen.setVisibility(View.INVISIBLE);
 currentScreen=newScreen;
 currentScreen.setVisibility(View.VISIBLE);
 theDisplay.bringChildToFront(currentScreen);
}

就是用于屏幕切换。
另外,有于程序主要移植于JavaME,并且主要目的是为了了解Android 平台,和 JavaME版相比不够完善,但基本功能是实现了,如有兴趣的可以进一步完善。

代码下载 Android版坦克大战    http://www.guidebee.info/download/android/battlecity/AndroidBattleCity.zip

                  Java ME版坦克大战 http://www.guidebee.info/download/android/battlecity/BattleCityJavaME.zip

 

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

本篇介绍坦克大战游戏中的主角,坦克类。游戏中坦克种类有多种,但主要特性大同小异。下图为游戏中定义的坦克类层次图。

Tank为所有坦克类的基类,它定义了几个主要的方法
  think() 思考,如有AI,算法在这里实现,对于简单坦克SimpleTank,可能随机选择一步,而对SmartTank来说,向靠近玩家坦克的方向前进一步。
  drive()  根据Think决定前进一步
 shoot() 根据当前条件决定发射一棵子弹。PlayerTank由玩家和可同时发射的子弹来控制,Enemy坦克一般随机控制是否要发射子弹。
基类每个游戏帧的操作如下

/**
 * Operation be done in each tick.
 */
public void tick(){
 if(isVisible()){
  think();
  drive();
  shoot();
 }
}

派生类中PlayerTank 和 SmartTank逻辑相对复杂一些,FastTank,和HeavyTank都是SimpleTank的子类,FastTank行驶速度较快,而HeavyTank可以承受多次子弹才会被击毁。
PlayerTank中需要处理玩家按键事件,用于控制上下左右以及发射子弹,还要处理升级功能,如吃到增加宝贝。它的
public void upgrade(Powerup powerup)用于处理升级功能。
而在SmartTank的Think方法,它要根据玩家坦克当前位置算出下一步的方向,以便可以不断向玩家坦克靠近,并发射子弹试图击毁玩家坦克。
这些坦克类都定义在om.pstreets.game.battlecity.actors.tank,代码中有较详细的注释,这里不详细一一说明了。

 

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

本篇介绍坦克大战游戏除坦克之外的几个角色。
1. Bullet 子弹类        坦克发射出的子弹在游戏中飞行
2.Explosion 爆炸类   子弹击中子弹,障碍物,或是坦克显示爆炸
3. Powerup 增强宝贝类  星星,加坦克,定时器等
4. Score 分数类。         击中坦克或是攻取增强宝贝,加分显示,分数有100,200,300,400,500,击中不同坦克分数不同。
为直观起见,参见下图,红圈里从上到下分别是Bullet, Powerup, Explosion, Score.

子弹类,屏幕中所有显示子弹从一个子弹池BULLET_POOL中取出,子弹有方向,速度,及强度等属性,高强度的子弹可以击破石块。
它每个游戏帧所要完成的操作如下。

/**
 * Operation be done in each tick.
 */
public void tick(){
 if (!isVisible() || direction==BattleField.NONE)
  return;
 // Move the bullet.
 move(dx, dy);
 int x = getRefPixelX();
 int y = getRefPixelY();
 PlayerTank playerTank=(PlayerTank)Tank.getTank(0);
 //outside the battle field, hitting the border
 if (x <= 0 || x >= battleField.getWidth() || y <= 0
   || y >= battleField.getHeight()) {

  //this is to avoid explosition outside the battlefield.
  if(x<=0) x=0;
  if(x >= battleField.getWidth()) x= battleField.getWidth();
  if(y<=0) y=0;
  if(y>= battleField.getHeight())y=battleField.getHeight();
  setPosition(x,y);
  explode();
  return;
 }
 
 // See if it hit a tank.
 if (friendly) {
  // See if it hit an enemy tank.
  for (int i = 1; i < Tank.POOL_SIZE; i++) {
   EnemyTank enemy = (EnemyTank)Tank.getTank(i);
   if (enemy!=null && enemy.isVisible() &&
     collidesWith(enemy, false)) {
    enemy.explode();
    explode();
    return;
   }
  }
 } else {
  // See if it hit player tank.
  
  if (collidesWith(playerTank, false)) {
   playerTank.explode();
   explode();
   return;
  }
 }
 
 //check to see if hit player's home
 if(Powerup.isHittingHome(this)){
  //TODO: Game Over
  explode();
  return;
 }
 // See if it hit a wall.
 if (battleField.hitWall(x, y, strength)) {
  explode();
  return;
 }
 
 // See if it hit another bullet.
 for (int i = 0; i < POOL_SIZE; i++) {
  Bullet anotherBullet=BULLET_POOL;
  if(this!=anotherBullet && anotherBullet.isVisible()){
   if (collidesWith(anotherBullet, false)) {
    explode();
    BULLET_POOL.explode();
    return;
   }
  }
 }
}

要判断是否击中墙壁,对方坦克,或是对方子弹,是否击中“家”,如果有,则爆炸,如都没有,则同方向前行一步。
爆炸类,子弹击中障碍物(墙,子弹,坦克)时显示爆炸动画效果。它有两种一个是大爆炸,一个是小爆炸。
它每个游戏帧所要完成的操作比较简单,每步显示一个动画帧,直到显示完。

/**
 * Operation be done in each tick.
 */
public void tick() {
 if (!isVisible())
  return;
 nextFrame();
 if (getFrame() == 0){
  setVisible(false);
 }
}

增强宝贝类,有多种,无敌,加坦克,地雷,定时器等。不同的增强宝贝可以使玩家获得不同的能力,玩过坦克大战游戏的人都比较熟悉。
在游戏进行中, 会不时或者当玩家打中红色坦克时,会有游戏中随机出现不同增强宝贝。
它每个游戏帧所要完成的操作如下:
如果玩家得到“无敌”增强功能时,“无敌”具有一定的时效性,需要判断无敌是否过时,其它时候则让该增强宝贝有闪烁效果,引起玩家注意。

/**
 * Operation be done in each tick.
 */
public void tick(){
 if(type==NOTHING || !isVisible()) return;
 long tickTime = System.currentTimeMillis();
 long refreshPeriod=MILLIS_PER_TICK;
 
 //invulnerable powerup is controlled by the player tank.
 if(type!=INVULNERABLE &&type!=HOME && type!=HOME_DESTROYED){
  if(tickTime-startTime>livePeriod){
   setFrame(NOTHING);
   setVisible(false);
   return;
  }
 }else{
  refreshPeriod=MILLIS_PER_TICK/10;
 }
 if(timeTaken>=refreshPeriod){
  showNextFrame=!showNextFrame;
  if(type==INVULNERABLE){
     if(showNextFrame){
    setFrame(0);
   }else{
    setFrame(1);
   }
  }else if(type==HOME || type==HOME_DESTROYED){
     setFrame(type);
  }else{
   if(showNextFrame){
    setFrame(type);
   }else{
    setFrame(NOTHING);
   }
  }
  timeTaken = System.currentTimeMillis() - tickTime;
 } else{
  timeTaken+=1;
 }
}

最后一个是分数类,比较简单,它每个游戏帧所要完成的操作如下

/**
 * Operation be done in each tick.
 */
public void tick(){
 if(isVisible()){
  long tickTime = System.currentTimeMillis();
  if(startTime>0){
   if(tickTime-startTime>livePeriod){
    setVisible(false);
    startTime=0;
    return;
   }
  }
 }
}

在屏幕上显示几秒种后消失。

 

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中填入石块,由于宝贝有时效性,到了一定时间后将“家”变回普通砖块做成。

 

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

有了游戏所需的图象及声音资源后,下面就可以开始定义游戏中的各种角色。为了方便起见,坦克大战游戏中定义了一个角色接口。

public interface Actor{

////////////////////////////////////////////////////////////////////////////

/**
* Operation be done in each tick.
*/
void tick();
}

该接口有一个tick方法,为每个游戏帧该角色所要完成的动作,比如说背景可能要更换图形以形成动画效果(如水面波浪)。坦克可以完成前面一步,子弹飞行等等。
坦克大战游戏中定义了背景类BattleField ,子弹Bullet,各种坦克类(Tank, PlayTank, EnemyTank, FastTank, HeavyTank, SimpleTank,  PlayerTank,SmartTank) , 升级法宝Powerup,以及动态显示的分数Score类,都实现了Actor接口。
而这些角色类同时又是Game API中 Layer的子类。因些游戏逻辑比较简单,下面代码是GameScene中线程Run的方法,为游戏进行时主线程

public void run(){
    Thread currentThread = Thread.currentThread();

    try {
        while (currentThread == animationThread) {
        long startTime = System.currentTimeMillis();
        // Don't advance game or draw if canvas is covered by a system
        // screen.
        if (isShown()) {
           tick();
        if(hasSurface){
           Canvas canvas=holder.lockCanvas();
           updateGame(canvas);
           holder.unlockCanvasAndPost(canvas);
        }
       }
      timeTaken = System.currentTimeMillis() - startTime;
      if (timeTaken < MILLIS_PER_TICK) {
        synchronized (this) {
          if(MILLIS_PER_TICK > timeTaken){
         wait(MILLIS_PER_TICK - timeTaken);
         timeTaken = System.currentTimeMillis() - startTime;
      }
     }
  } else {
        Thread.yield();
    }
}
   } catch (InterruptedException e) {
}

}

而其中的tick()方法就是调用游戏中所有角色的tick()方法:

private void tick(){

for(int i=0;i<TOTALLAYERS;I++){
Layer layer=layerManager.getLayerAt(i);
if(layer.isVisible()){
Actor actor=(Actor)layer;

actor.tick();
}
}
applyGameLogic();
}

这样参与游戏中的各个角色完成自已每帧所需要更新,整个游戏就动起来了。

在后面的文章将主要介绍各个角色类的基本实现方法。

 

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

游戏中使用图象及声音资源
坦克大战游戏中用到游戏资源(音效及图片)来自网络。
这里先对游戏用到的资源做个说明
音效 snd1–snd2 格式为 midi 用于过场音乐及字弹发射及爆炸音效。
图片
img1 – img5 为游戏中各种坦克,物体的分解图片。
其中 img1 由下面图片组成
   各种增强宝贝 (最左边两个是家,和炸毁的家),依次为加一辆,定时器等等
   坦克或子弹爆炸动画效果
      子弹(四个方向飞行)
     我方坦克动画(四个方向及履带动态效果),最右方为无敌时状态
多种敌方坦克

img2 由下列图片组成
     雪地
     砖块
     树林
    水面 (两片可以形成水面动态效果)
      石头(一般情况下不能被坦克打穿)

img 3 由下列图片组成
   开始画面
分数画面
  显示玩家剩余坦克数
     显示剩余敌方坦克数

img4由下列图片组成
     显示分数

     显示第几关
img5由下列图片组成

imgX 格式为这些PNG图片连接而成。如何读取请参见代码中的ResourceManager ,这些图片可以在程序包中的Resources目录中找到,代码中实际用到的资源snd1-snd5,img1-img5 在 src 目录下。
资源下载 http://www.guidebee.info/download/android/battlecity/resources.zip