J2ME遊戲開發例項講解(下)(轉)

post0發表於2007-08-12
J2ME遊戲開發例項講解(下)(轉)[@more@]

  五、詳細設計

  

  詳細設計是程式開發過程中至關重要的一個環節,好在我們在前面的各個階段中已經搭建好了專案所需的一些工具,現在這個階段中我們只需集中精力設計好Displayable1中的邏輯。(兩天的時間當然不只幹這點活,還要把其他幾個類的設計修改一下)

  

  Displayable1這個類負責處理程式的控制邏輯。首先,它需要有表示當前關面的變數level、表示當前游標位置的變數loc、表示要移動區域的變數SelectArea、表示要移動到的區域的變數MoveArea、表示是否已有區域被選中而準備移動的變數Selected和Map類的例項MyMap。然後,我們根據使用者按不同的鍵來處理不同的訊息,我們要實現keyPressed()函式,在函式中我們處理按鍵的上下左右和選中(Fire),這裡的處理需要我展開來講一講,後面我很快會把這一部分詳細展開。

  

  接下來,是實現paint()函式,我們打算在這一部分中反覆的重畫背景、地圖和選擇區域,這個函式必須處理好區域被選中之後的畫筆顏色的切換,具體講就是在沒有選中任何區域時要用黑色畫筆,當選重要移動的區域時使用綠色畫筆,當選擇要移動到的區域時改用紅色畫筆(當然附加一張流程圖是必不可少的)。

  

  再下面要實現的setRange()函式和setMoveRange()函式,這兩個函式用來設定要移動的區域和要移動到的區域,我的思路就是利用前面在Images類中介紹過的地圖組合標記常量,當移動到地圖組合標記常量時,根據該點地圖中的值做逆向變換找到相應的地圖示記常量,然後設定相應的loc、SelectArea和MoveArea,其中setMoveRange()函式還用到了一個輔助函式isInRange(),isInRange()函式是用來判斷給定的點是否在已選中的要移動的區域之內,如果isInRange()的返回值是假並且該點處的值不是空白就表明要移動到的區域侵犯了其他以被佔用的區域。有了setRange()和setMoveRange()函式,Move()函式就水到渠成了,Move()函式將要移動的區域移動到要移動到的區域,在移動過程中分為三步進行:

  

  第一.複製要移動的區域;

  

  第二.將複製出的要移動區域複製到要移動到的區域(這兩步分開進行的目的是防止在複製過程中覆蓋掉要移動的區域);

  

  第三.用isInRange2()判斷給定的點是否在要移動到的區域內,將不在要移動到的區域內的點設定成空白。

  

  下面我們詳細的分析一下keyPressed()函式的實現方法:首先,keyPressed()函式要處理按鍵的上下左右和選中(Fire),在處理時需要用Canvas類的getGameAction函式來將按鍵的鍵值轉換成遊戲的方向,這樣可以提高遊戲的相容性(因為不同的J2ME實現,其方向鍵的鍵值不一定是相同的)。

  

  接下來,分別處理四個方向和選中.當按下向上時,先判斷是否已經選定了要移動的區域(即this.selected是否為真),如果沒有選中要移動區域則讓游標向上移動一格,然後呼叫setRange()函式設定選擇要移動的區域,再呼叫repaint()函式重新整理螢幕,否則如果已經選中了要移動的區域,就讓游標向上移動一格,然後呼叫setMoveRange()函式判斷是否能夠向上移動已選中的區域,如果能移動就呼叫repaint()函式重新整理螢幕,如果不能移動就讓游標向下退回到原來的位置。

  

  當按下向下時,先判斷是否已經選定了要移動的區域,如果沒有選中要移動的區域則判斷當前所處的區域是否為兩個格高,如果是兩個格高則向下移動兩格,如果是一個格高則向下移動一格,接著再呼叫setRange()函式設定選擇要移動的區域,而後呼叫repaint()函式重新整理螢幕,否則如果已經選中了要移動的區域,就讓游標向下移動一格,然後呼叫setMoveRange()函式判斷是否能夠向下移動已選中的區域,如果能移動就呼叫repaint()函式重新整理螢幕,如果不能移動就讓游標向上退回到原來的位置.按下向左時情況完全類似向上的情況,按下向右時情況完全類似向下的情況,因此這裡不再贅述,詳細情況請參見程式的原始碼。

  

  當按下選中鍵時,先判斷是否已經選中了要移動的區域,如果已經選中了要移動的區域就呼叫Move()函式完成由要移動的區域到要移動到的區域的移動過程,接著呼叫repaint()函式重新整理螢幕,然後將已選擇標記置成false,繼續呼叫win()函式判斷是否完成了任務,否則如果還沒有選定要移動的區域則再判斷當前選中區域是否為空白,如果不是空白就將選中標記置成true,然後重新整理螢幕.這裡介紹一個技巧,在開發程式遇到複雜的邏輯的時候,可以構造一格列印函式來將所關心的資料結構列印出來以利除錯,這裡我們就構造一個PrintGrid()函式,這個函式純粹是為了除錯之用,效果這得不錯.至此我們完成了編碼前的全部工作。

  

  六、編碼

  

  整個專案共有五個類,有四個類的程式碼前面已經介紹過了,而且是在其他專案中使用過的相對成熟的程式碼.現在只需全力去實現Displayable1類.Displayable1類的程式碼如下:

  

  package huarongroad;

  

  import javax.microedition.lcdui.*;

  

  public class Displayable1 extends Canvas implements CommandListener {

  

  private int[] loc = new int[2]; <A href="file://光">file://光</A>標的當前位置,0是水平位置,1是豎直位置

  private int[] SelectArea = new int[4];//被選定的區域,即要移動的區域

  private int[] MoveArea = new int[4];//要移動到的區域

  private Map MyMap = new Map();//地圖類

  private boolean selected;//是否已經選中要移動區域的標誌

  private int level;//但前的關面

  public Displayable1() {//建構函式

  try {

  jbInit();//JBuilder定義的初始化函式

  }catch (Exception e) {

  e.printStackTrace();

  }

  }

  

  private void Init_game(){

  //初始化遊戲,讀取地圖,設定選擇區域,清空要移動到的區域

  this.loc = MyMap.read_map(this.level);//讀取地圖檔案,並返回游標的初始位置

  //0為水平位置,1為豎直位置

  this.SelectArea[0] = this.loc[0];//初始化選中的區域

  this.SelectArea[1] = this.loc[1];

  this.SelectArea[2] = 1;

  this.SelectArea[3] = 1;

  this.MoveArea[0] = -1;//初始化要移動到的區域

  this.MoveArea[1] = -1;

  this.MoveArea[2] = 0;

  this.MoveArea[3] = 0;

  }

  

  private void jbInit() throws Exception {//JBuilder定義的初始化函式

  <A href="file://初">file://初</A>始化例項變數

  this.selected = false;//設定沒有被選中的要移動區域

  this.level = 1;

  Images.init();//初始化圖片常量

  Init_game();//初始化遊戲,讀取地圖,設定選擇區域,清空要移動到的區域

  setCommandListener(this);//新增命令監聽,這是Displayable的例項方法

  addCommand(new Command("Exit", Command.EXIT, 1));//新增“退出”按鈕

  }

  

  public void commandAction(Command command, Displayable displayable) {

  //命令處理函式

  if (command.getCommandType() == Command.EXIT) {//處理“退出”

  MIDlet1.quitApp();

  }

  }

  

  protected void paint(Graphics g) {

  //畫圖函式,用於繪製使用者畫面,即顯示圖片,勾畫選中區域和要移動到的區域

  try {

  g.drawImage(Images.image_Frame, 0, 0, Graphics.TOP | Graphics.LEFT);//畫背景

  MyMap.draw_map(g);//按照地圖內容畫圖

  if ( this.selected )

  g.setColor(0,255,0);//如果被選中,改用綠色畫出被選中的區域

  g.drawRect(this.SelectArea[0] * Images.UNIT + Images.LEFT, this.SelectArea[1] * Images.UNIT + Images.TOP, this.SelectArea[2] * Images.UNIT, this.SelectArea[3] * Images.UNIT);//畫出選擇區域,

  <A href="file://如">file://如</A>果被選中,就用綠色

  <A href="file://否">file://否</A>則,使用黑色

  g.setColor(255,255,255);//恢復畫筆顏色

  if (this.selected) {//已經選中了要移動的區域

  g.setColor(255, 0, 255);//改用紅色

  g.drawRect(this.MoveArea[0] * Images.UNIT + Images.LEFT, this.MoveArea[1] * Images.UNIT + Images.TOP, this.MoveArea[2] * Images.UNIT, this.MoveArea[3] * Images.UNIT);//畫出要移動到的區域

  g.setColor(255, 255, 255);//恢復畫筆顏色

  }

  }catch (Exception ex) {

  }

  System.out.println(Runtime.getRuntime().freeMemory());

  System.out.println(Runtime.getRuntime().totalMemory());

  }

  

  private void setRange() {

  //設定移動後能夠選中的區域

  //調整當前游標位置到地圖的主位置,即記錄人物資訊的位置

  if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFT) {

  this.loc[0] -= 1;//向左調

  }else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DUP) {

  this.loc[1] -= 1;//向上調

  }else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFTUP) {

  this.loc[0] -= 1;//向左調

  this.loc[1] -= 1;//向上調

  }

  this.SelectArea[0] = this.loc[0];//設定游標的水平位置

  this.SelectArea[1] = this.loc[1];//設定游標的豎直位置

  //設定游標的寬度

  if (this.loc[0] + 1 < Images.WIDTH) {

  this.SelectArea[2] = this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] != (byte) '1' ? 1 : 2;

  }else {

  this.SelectArea[2] = 1;

  }

  //設定游標的高度

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-951691/,如需轉載,請註明出處,否則將追究法律責任。

相關文章