華容道遊戲開發--android小組
這個是我們小組的同學做的一個遊戲,遊戲介面做的比較簡單一點,但是還是麻雀雖小五臟俱全滴。。。
1,遊戲背景
華容道是古老的中國遊戲,以其變化多端、百玩不厭的特點與七巧板、九連環合稱“中國的難題”。
華容道遊戲取自著名的三國故事,曹操在赤壁大戰中被劉備和孫權的“苦肉計”、“火燒連營”打敗,被迫退逃到華容道,又遇上諸葛亮的伏兵,關羽為了報答曹操對他的恩情,明逼實讓,終於幫助曹操逃出了華容道。
遊戲就是依照“曹瞞兵敗走華容,正與關公狹路逢。只為當初恩義重,放開金鎖走蛟龍”這一故事情節進行設計的。
2,功能簡介
遊戲的操作非常簡單,其具體方法如下:
(1)運行遊戲,首先進入的是主選單介面,如圖1所示。
(2)在選單介面,可以通過“開啟聲音”/“關閉聲音”來控制遊戲聲音的開關,單擊幫助選單可進入幫助介面,如圖2所示。
(3)在選單介面單擊“開始遊戲”可進入遊戲的主介面,如圖3所示
(4)在遊戲介面,玩家可以通過單擊人物圖片,對人物進行移動;可以單擊聲音按鈕控制遊戲聲音;單擊“上一關”或“下一關”按鈕選擇關卡;單擊“重玩”可以從頭開始玩本關。如圖4所示。
(5)當“曹操”被移動到棋盤最下方的綠線處時,遊戲勝利。遊戲會記錄當前已走的步數,以及每一關的歷史最好成績。
(6)在遊戲過程中,玩家可以單擊X處,結束遊戲,回到主選單。圖2 遊戲簡介
1,遊戲背景
華容道是古老的中國遊戲,以其變化多端、百玩不厭的特點與七巧板、九連環合稱“中國的難題”。
華容道遊戲取自著名的三國故事,曹操在赤壁大戰中被劉備和孫權的“苦肉計”、“火燒連營”打敗,被迫退逃到華容道,又遇上諸葛亮的伏兵,關羽為了報答曹操對他的恩情,明逼實讓,終於幫助曹操逃出了華容道。
遊戲就是依照“曹瞞兵敗走華容,正與關公狹路逢。只為當初恩義重,放開金鎖走蛟龍”這一故事情節進行設計的。
2,功能簡介
遊戲的操作非常簡單,其具體方法如下:
(1)運行遊戲,首先進入的是主選單介面,如圖1所示。
(2)在選單介面,可以通過“開啟聲音”/“關閉聲音”來控制遊戲聲音的開關,單擊幫助選單可進入幫助介面,如圖2所示。
(3)在選單介面單擊“開始遊戲”可進入遊戲的主介面,如圖3所示
(
(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的基礎知識有了更深入的瞭解,也為以後大型遊戲和應用的開發打好了基礎。