华容道游戏开发--android小组

这个是我们小组的同学做的一个游戏,游戏界面做的比较简单一点,但是还是麻雀虽小五脏俱全滴。。。

1,游戏背景

华容道是古老的中国游戏,以其变化多端、百玩不厌的特点与七巧板、九连环合称“中国的难题”。

华容道游戏取自著名的三国故事,曹操在赤壁大战中被刘备和孙权的“苦肉计”、“火烧连营”打败,被迫退逃到华容道,又遇上诸葛亮的伏兵,关羽为了报答曹操对他的恩情,明逼实让,终于帮助曹操逃出了华容道。

游戏就是依照“曹瞒兵败走华容,正与关公狭路逢。只为当初恩义重,放开金锁走蛟龙”这一故事情节进行设计的。

2,功能简介

游戏的操作非常简单,其具体方法如下:

(1)运行游戏,首先进入的是主菜单界面,如图1所示。

(2)在菜单界面,可以通过“打开声音”/“关闭声音”来控制游戏声音的开关,单击帮助菜单可进入帮助界面,如图2所示。

(3)在菜单界面单击“开始游戏”可进入游戏的主界面,如图3所示

(4)在游戏界面,玩家可以通过单击人物图片,对人物进行移动;可以单击声音按钮控制游戏声音;单击“上一关”或“下一关”按钮选择关卡;单击“重玩”可以从头开始玩本关。如图4所示。

(5)当“曹操”被移动到棋盘最下方的绿线处时,游戏胜利。游戏会记录当前已走的步数,以及每一关的历史最好成绩。

(6)在游戏过程中,玩家可以单击X处,结束游戏,回到主菜单。

图2 游戏简介

1,游戏背景

华容道是古老的中国游戏,以其变化多端、百玩不厌的特点与七巧板、九连环合称“中国的难题”。

华容道游戏取自著名的三国故事,曹操在赤壁大战中被刘备和孙权的“苦肉计”、“火烧连营”打败,被迫退逃到华容道,又遇上诸葛亮的伏兵,关羽为了报答曹操对他的恩情,明逼实让,终于帮助曹操逃出了华容道。

游戏就是依照“曹瞒兵败走华容,正与关公狭路逢。只为当初恩义重,放开金锁走蛟龙”这一故事情节进行设计的。

2,功能简介

游戏的操作非常简单,其具体方法如下:

1)运行游戏,首先进入的是主菜单界面,如图1所示。

2)在菜单界面,可以通过“打开声音”/“关闭声音”来控制游戏声音的开关,单击帮助菜单可进入帮助界面,如图2所示。

3)在菜单界面单击“开始游戏”可进入游戏的主界面,如图3所示

4)在游戏界面,玩家可以通过单击人物图片,对人物进行移动;可以单击声音按钮控制游戏声音;单击“上一关”或“下一关”按钮选择关卡;单击“重玩”可以从头开始玩本关。如图4所示。

5)当“曹操”被移动到棋盘最下方的绿线处时,游戏胜利。游戏会记录当前已走的步数,以及每一关的历史最好成绩。

6)在游戏过程中,玩家可以单击X处,结束游戏,回到主菜单。

  

 

                   图1 游戏主菜单 

                   

 图2 游戏简介

                  图3 游戏主界面

  

3,游戏的策划及准备工作

l  游戏类型

该游戏属于中国传统益智游戏,其操作方式类似拼图,游戏变化多端,百玩不厌。

l  运行平台

目标平台为Android2.2,但开发过程中采用的技术都是Android的基础技术,所以在低版本的Android平台上也可以正常运行。

l  操作方式

本游戏采用屏幕事件进行操作,玩家可使用触控笔单击屏幕来完成对游戏的控制。

l  音效设计

考虑到玩家的体验,并结合游戏的背景,我们选择了“三国杀”的音乐作为背景音乐,游戏过程中,移动曹操时,还会有特别的音效。

l  游戏开发的准备工作

游戏开发前的准备工作是必不可少的,主要是要搜集需要用到的图片、声音等资源。本游戏的开发过程中用到的资源主要有以下几大类:

图片资源:

(1)人物头像(2)菜单及按钮(3)关卡名称(4)游戏背景界面

图4 头像图片

图5 按钮

图6 关卡名称

声音资源:

背景音乐:gamesound.wav

移动曹操时的音乐:caocaosound.wav

游戏胜利有的音乐:caocao_succed.wav

4,游戏的架构

我们将游戏中的类分成3部分,下面分别对其进行介绍

4.1,共有类

Activity的实现类Huarongdao.java。该类是通过扩展基类Activity得到的,是整个游戏的控制器,也是整个程序的入口。

Huarongdao类实现代码如下:

public class Huarongdao extends Activity {

    boolean isSound = true;//是否播放声音

    MediaPlayer gamesound;//游戏声音

    MediaPlayer caocaoSound;

    MediaPlayer caocaoSucceed;

    static int CURRENT_LEVEL=0;

    static int[] bestSteps=new int[Maps.LEVEL_NUM];

    String[] level=new String[]{"level0","level1","level2","level3","level4","level5","level6","level7","level8","level9"};

    Handler myHandler = new Handler(){//用来更新UI线程中的控件

        public void handleMessage(Message msg) {

        if(msg.what == 1){//MenuView传来的消息,切换到GameView

             initGameView();//初始化并切换到游戏界面

        }

        else if(msg.what ==2){//MenuView传来的消息,切换到HelpView

             initHelpView();//初始化并切换到帮助界面

        }

        else if(msg.what==3){

             initMenuView();//切换到menuview

        }

        }

    };

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        //全屏

        requestWindowFeature(Window.FEATURE_NO_TITLE);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN

                  WindowManager.LayoutParams.FLAG_FULLSCREEN);

        gamesound  = MediaPlayer.create(this, R.raw.gamesound);//游戏过程的背景声音

        caocaoSound=MediaPlayer.create(this, R.raw.caocaosound);//游戏过程中曹操移动时的声音

        caocaoSucceed=MediaPlayer.create(this, R.raw.caocao_succeed);//游戏过程的背景声音

       gamesound.setLooping(true);//设置游戏声音循环播放

       caocaoSound.setLooping(false);

       caocaoSucceed.setLooping(false);

       //从preferences中读取出每一关的最好成绩

       SharedPreferences beststeps=getPreferences(Activity.MODE_PRIVATE);

       for(int i=0;i<Maps.LEVEL_NUM;i++)

       bestSteps[i]=beststeps.getInt(level[i], 0);     

        this.initMenuView();//初始化菜单界面

       

    }

    private void initMenuView() {

       // TODO Auto-generated method stub

       if(this.isSound){//是否播放声音

        gamesound.start();//播放声音

    }

       this.setContentView(new MenuView(this,this));

      

    }

    protected void initHelpView() {

       // TODO Auto-generated method stub

       this.setContentView(new HelpView(this,this));

      

    }

    protected void initGameView() {

       // TODO Auto-generated method stub

       this.setContentView(new GameView(this,this));

      

    }

    public void updateBestSteps() {

       // TODO Auto-generated method stub

       SharedPreferences newsteps=getPreferences(0);

       SharedPreferences.Editor editor=newsteps.edit();

       editor.putInt(level[CURRENT_LEVEL], bestSteps[CURRENT_LEVEL]);

       editor.commit();

      

    }

4.2,辅助界面相关类

有3个:菜单界面类MenuView,为菜单界面的实现类,负责绘制菜单界面以及对菜单界面的屏幕进行监听。

MenuView类的实现如下:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MenuView extends SurfaceView implements SurfaceHolder.Callback{
 Huarongdao activity;
 Bitmap startGame;
 Bitmap openSound;
 Bitmap closeSound;
 Bitmap help;
 Bitmap exit;
 private TutorialThread thread;//刷帧的线程
 
 

 public MenuView(Context context,Huarongdao huarongdao) {
  super(context);
  // TODO Auto-generated constructor stub
  this.activity=huarongdao;//得到huarongdao引用
  getHolder().addCallback(this);
        this.thread = new TutorialThread(getHolder(), this);//启动刷帧线程
  initBitmap();
 }


 private void initBitmap() {
  // TODO Auto-generated method stub
  startGame = BitmapFactory.decodeResource(getResources(), R.drawable.startgame);//开始游戏按钮
  openSound = BitmapFactory.decodeResource(getResources(), R.drawable.opensound);//开始声音按钮
  closeSound = BitmapFactory.decodeResource(getResources(), R.drawable.closesound);//关闭声音按钮
  help = BitmapFactory.decodeResource(getResources(), R.drawable.help);//帮助按钮
  exit = BitmapFactory.decodeResource(getResources(), R.drawable.exit);//退出按钮  
 }
 
 public void onDraw(Canvas canvas){
  canvas.drawColor(Color.BLACK);//清屏
  canvas.drawBitmap(startGame, 50, 50, null);//绘制图片
  if(activity.isSound){//放声音时,绘制关闭声音图片
   canvas.drawBitmap(closeSound, 50, 150, null);//绘制关闭声音
  }else{//没有放声音时绘制打开声音图片
   canvas.drawBitmap(openSound, 50, 150, null);//绘制开始声音
  }
  canvas.drawBitmap(help, 50, 250, null);//绘制帮助按钮
  canvas.drawBitmap(exit, 50, 350, null);//绘制退出按钮
  
 }
 public boolean onTouchEvent(MotionEvent event) {//屏幕监听
  if(event.getAction() == MotionEvent.ACTION_DOWN){
   if(event.getX()>105 && event.getX()<220
     &&event.getY()>60 && event.getY()<95){//点击的是开始游戏
    activity.myHandler.sendEmptyMessage(1);
   }
   
   else if(event.getX()>105 && event.getX()<220
     &&event.getY()>160 && event.getY()<195){//点击的是声音按钮
    activity.isSound = !activity.isSound;//将声音开关取反
    if(!activity.isSound){//当没有放声音时
     if(activity.gamesound != null){//检查当前是否已经有声音正在播放
      if(activity.gamesound.isPlaying()){//当游戏声音正在播放时,
       activity.gamesound.pause();//停止声音的播放
      } 
     }
    }else{//当需要播放声音时
     if(activity.gamesound != null){//当gamesound不为空时
      if(!activity.gamesound.isPlaying()){//且当前声音没有在播放
       activity.gamesound.start();//则播放声音
      } 
     }
    }
   }
   
   else if(event.getX()>105 && event.getX()<220
     &&event.getY()>260 && event.getY()<295){//点击的是帮助按钮
    activity.myHandler.sendEmptyMessage(2);//向activity发送Hander消息通知切换View
   }else if(event.getX()>105 && event.getX()<220
     &&event.getY()>360 && event.getY()<395){//点击的是退出游戏
    
    
    System.exit(0);//直接退出游戏
   }
  }
  return super.onTouchEvent(event);
 }
 
 class TutorialThread extends Thread{//刷帧线程
  private int span = 500;//睡眠的毫秒数
  private SurfaceHolder surfaceHolder;//SurfaceHolder的引用
  private MenuView menuView;//MenuView的引用
  private boolean flag = false;//循环标记位
        public TutorialThread(SurfaceHolder surfaceHolder, MenuView menuView) {//构造器
            this.surfaceHolder = surfaceHolder;//得到surfaceHolder引用
            this.menuView = menuView;//得到menuView引用
        }
        public void setFlag(boolean flag) {//设置循环标记位
         this.flag = flag;
        }
  public void run() {//重写的run方法
   Canvas c;//画布
            while (this.flag) {//循环
                c = null;
                try {
                 // 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null
                    c = this.surfaceHolder.lockCanvas(null);
                    synchronized (this.surfaceHolder) {//同步锁
                     menuView.onDraw(c);//调用绘制方法
                    }
                } finally {//使用finally保证下面代码一定被执行
                    if (c != null) {
                     //更新屏幕显示内容
                        this.surfaceHolder.unlockCanvasAndPost(c);
                    }
                }
                try{
                 Thread.sleep(span);//睡眠指定毫秒数
                }catch(Exception e){//捕获异常
                 e.printStackTrace();//有异常时打印异常堆栈信息
                }
            }
  }
 }

 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height) {
  // TODO Auto-generated method stub
  
 }


 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  this.thread.setFlag(true);//设置循环标志位
        this.thread.start();//启动线程
  
 }


 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  boolean retry = true;//循环标志位
        thread.setFlag(false);//设置循环标志位
        while (retry) {//循环
            try {
                thread.join();//等待线程结束
                retry = false;//停止循环
            }catch (InterruptedException e){}//不断地循环,直到刷帧线程结束
        }
  
 }

}

HelpView,实现帮助界面。Maps用于存放关卡布局信息,如果要新增关卡,只需修改这个类即可。

HelpView实现如下:

public class HelpView extends SurfaceView implements SurfaceHolder.Callback{

    Bitmap bg;

    Bitmap introduction;

    Bitmap exit2;

    Huarongdao activity;

    int intro_y=480;//文字的y坐标

    private TutorialThread thread;//刷帧的线程

   

   

    public HelpView(Context context,Huarongdao huarongdao) {

       super(context);

       // TODO Auto-generated constructor stub

       this.activity=huarongdao;//得到huarongdao引用

       getHolder().addCallback(this);

        this.thread = new TutorialThread(getHolder(), this);//启动刷帧线程

       initBitmap();

    }

   

    public void onDraw(Canvas canvas){

       canvas.drawColor(Color.BLACK);//清屏

       canvas.drawBitmap(bg, 0, 0, null);//绘制背景图片

      

       canvas.drawBitmap(introduction, 0, intro_y, null);//绘制文字介绍

       if(intro_y==0)

       canvas.drawBitmap(exit2, 240, 440, null);// 绘制退出按钮

      

    }

   

    public boolean onTouchEvent(MotionEvent event) {

       if (event.getAction() == MotionEvent.ACTION_DOWN) {// 只取鼠标按下的事件

           if (event.getX() > 240 && event.getX() < 280

                  && event.getY() > 440

                  && event.getY() < 480) {// 按下了退出按钮

              activity.myHandler.sendEmptyMessage(3);// 发送消息,切换到MenuView

           }     

       }

       return super.onTouchEvent(event);

    }

 

 

    private void initBitmap() {

       // TODO Auto-generated method stub

       bg=BitmapFactory.decodeResource(getResources(), R.drawable.bg);

       introduction=BitmapFactory.decodeResource(getResources(), R.drawable.introduction);

       exit2=BitmapFactory.decodeResource(getResources(), R.drawable.exit2);

      

    }

 

 

    @Override

    public void surfaceChanged(SurfaceHolder holder, int format, int width,

           int height) {

       // TODO Auto-generated method stub

      

    }

 

 

    @Override

    public void surfaceCreated(SurfaceHolder holder) {

       // TODO Auto-generated method stub

       this.thread.setFlag(true);//设置循环标志位

        this.thread.start();//启动线程

    }

 

    @Override

    public void surfaceDestroyed(SurfaceHolder holder) {

       // TODO Auto-generated method stub

       boolean retry = true;//循环标志位

        thread.setFlag(false);//设置循环标志位

        while (retry) {//循环

            try {

                thread.join();//等待线程结束

                retry = false;//停止循环

            }catch (InterruptedException e){}//不断地循环,直到刷帧线程结束

        }

      

    }

   

    class TutorialThread extends Thread{//刷帧线程

       private int span = 100;//睡眠的毫秒数

       private SurfaceHolder surfaceHolder;//SurfaceHolder的引用

       private HelpView helpView;

       private boolean flag = false;//循环标记位

        public TutorialThread(SurfaceHolder surfaceHolder, HelpView helpView) {//构造器

            this.surfaceHolder = surfaceHolder;//得到surfaceHolder引用

            this.helpView = helpView;

        }

        public void setFlag(boolean flag) {//设置循环标记位

        this.flag = flag;

        }

       public void run() {//重写的run方法

           Canvas c;//画布

            while (this.flag) {//循环

                c = null;

                try {

                  // 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null

                    c = this.surfaceHolder.lockCanvas(null);

                    synchronized (this.surfaceHolder) {//同步锁

                       helpView.onDraw(c);//调用绘制方法

                    }

                } finally {//使用finally保证下面代码一定被执行

                    if (c != null) {

                       //更新屏幕显示内容

                        this.surfaceHolder.unlockCanvasAndPost(c);

                    }

                }

                try{

                  Thread.sleep(span);//睡眠指定毫秒数

                  if(intro_y>0)

                  intro_y-=3;

                }catch(Exception e){//捕获异常

                  e.printStackTrace();//有异常时打印异常堆栈信息

                }

            }

       }

    }

 }

 

4.3,游戏界面相关类

GameView.java是本游戏中最主要的类,负责绘制游戏过程中所有的信息,如布局、最好成绩、关卡名、各个按钮等。该类中还包含了一个非常重要的线程TutorialThread,它负责游戏界面的定时刷新。

GameView是本游戏中最重要的类,它继承了SurfaceView,同时实现了SurfaceHolder.Callback,重写了屏幕监听方法onTouchEvent(MotionEvent event),该类中还包含了一个刷帧的线程TutorialThread,每隔一段时间调用一次GameView的onDraw方法进行屏幕的重绘。

    在数据存储方面,考虑到本游戏需要存储的数据只有“最好成绩”这一项,所以我们没有采用数据库,而是使用了轻量级的Preference存储方案。Preference主要用于存储和查询简单数据类型的数据,这些简单数据类型包括boolean,int,float,long以及string等,存储方式以键值对的形式存放在应用程序的私有文件夹下。

5,游戏的优化与改进

经过我们的努力,游戏的基本功能已经完成,但是有很多地方可以提升。例如,现在的版本中,我们需要先选中人物,再点击空格位置,才能移动人物。更好的方法是,点击人物后,就自动移动到空位置。此外,游戏的界面还可以做的更漂亮一些。

通过这个小游戏的开发,我们加深了对Android操作系统的认识,对Android的基础知识有了更深入的了解,也为以后大型游戏和应用的开发打好了基础。

posted @ 2011-03-19 10:03  华工微软俱乐部科技部  阅读(1815)  评论(2编辑  收藏  举报