1. 程式人生 > >華容道遊戲開發--android小組

華容道遊戲開發--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的基礎知識有了更深入的瞭解,也為以後大型遊戲和應用的開發打好了基礎。