【ZT】基於Nokia手機的移動遊戲開發步步通

作者: wayne編譯
時間: 2003-09-09

一、遊戲開發策略

  1 遊戲動作(Action)的使用

  MIDP的Canvas類讓程序員處理某些按鍵事件,要麼作爲特定的低級鍵控代碼事件要麼作爲抽象的遊戲動作。FullCanvas是Nokia的全屏畫布(FullCanvas)類,它是從Canvas類繼承而來的。

  在回合制遊戲或者不需要超過四個方向鍵(上、下、左、右)的遊戲中,最好使用直接的鍵盤代碼來控制遊戲動作。可以使用抽象遊戲動作的遊戲例子包括國際象棋和知識測驗以及解謎遊戲,這些都是使用方向鍵來滾動屏幕或者移動。
遊戲動作應該只在不需要快速反應的遊戲中使用。這是因爲所選擇的設備的遊戲動作映射可能對於要求快速動作的遊戲並不適用。並且,如果一個遊戲要求斜的方 向鍵或者這個遊戲是一個快節奏的動作遊戲,那時遊戲者一隻手需要移動遊戲角色,另一隻手需要執行其他操作,比如射擊、開門等等,那麼就需要使用直接鍵盤代 碼。原因是在MIDP中沒有斜向的遊戲動作,並且遊戲動作映射是爲一隻手使用設計的。

  當使用直接鍵盤代碼事件的時候,必須特別注意應用程序的可移植性。
在不同的設備之間鍵盤的佈局有很大區別(參見圖1,是兩種手機不同的鍵盤佈局)。開發者可以通過允許用戶在遊戲中自己定義按鍵的方式來解決這個問題。這可以在遊戲開始之前或者在遊戲的"選項"頁面中完成。

  鍵盤代碼和遊戲動作在同一個應用程序中決不應該混合使用。


圖1、不同手機的鍵盤佈局

  2 關於遊戲動作的說明

  一個MIDlet應用程序通過調用Canvas方法來探測哪些鍵盤代碼映射到運行的應用程序中的抽象遊戲動作:

public static int getGameAction(int keyCode);

  Canvas類定義抽象遊戲動作集:UP、DOWN、LEFT、RIGHT、FIRE等等。

  遊戲開發者應該知道MIDP 1.0規範中的一個問題。這個類定義了轉化鍵盤代碼到遊戲動作的方法,同樣也定義了轉化遊戲動作到鍵盤代碼的方法。

public int getGameAction(int keyCode)
public int getKeyCode(int gameAction)

   方法getKeyCode(int gameAction)可能會導致一些問題,因爲它只能返回基於遊戲動作的一個鍵盤代碼,即使MIDP 1.0允許超過一個鍵盤代碼被實現。在Nokia手機中,個別的一些鍵盤代碼被映射到相同的遊戲動作,比如"UP鍵"和"2鍵"都被映射爲向上的遊戲動 作。而這個方法只能返回其中之一;返回的值是特定的實現。然而,如果方法getGameAction(int KeyCode)使用"UP鍵"和"2鍵"的鍵盤代碼作爲參數,這個方法將返回正確的向上的遊戲動作。下面來看一個不好的例子,以加深我們的印象:

//不好的例子,不要這麼做:
class TetrisCanvas extends Canvas {
int leftKey, rightKey, downKey, rotateKey;
void init (){
//FOLLOWING MUST NOT BE DONE
leftKey = getKeyCode(LEFT);
rightKey = getKeyCode(RIGHT);
downKey = getKeyCode(DOWN);
rotateKey = getKeyCode(FIRE);
}
public void keyPressed(int keyCode) {
if (keyCode == leftKey) {
moveBlockLeft();
} else if (keyCode = rightKey) {
...
}
}
}

  下面是更好的解決方案:

class TetrisCanvas extends Canvas {
void init (){
}
public void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
switch (action)
{
case Canvas.LEFT:
moveBlockLeft();
break;
case Canvas.RIGHT:
moveBlockRight();
break;
}
}
}

   這個例子是MIDP 1.0規範中的例子,使用getKeyCode ( int gameAction)處理鍵盤代碼值,只能返回一個值。如果這樣的話,其它可能的按鍵映射就不能在MIDlet中使用了。比如說,在Nokia 7650中就會出現問題,Nokia 7650有五個方向鍵和一個操縱桿以及普通的鍵盤佈局,上面這個例子就會返回操縱桿的值而不是鍵盤的值。這是處理事件的一種與設備無關的方法,也是一種不 好的方法。更好的解決方法是在keyPressed ()方法內使用getGameAction ( int KeyCode)。通常,應用程序應該避免使用getKeyCode ( int gameAction)方法並且總是使用getGameAction ( int KeyCode)。

  3 遊戲外殼和遊戲動作

  Nokia新型號手機支持的遊戲外殼可能會影響遊戲動作。 Nokia第一款可以使用遊戲外殼的手機是Nokia 3510i(參見圖2)。如果手機支持遊戲外殼,設備的遊戲菜單中會有一個設置對話框,允許用戶設置遊戲外殼上的按鍵對應的遊戲動作。用戶必須設置這個按 鍵映射,否則設計使用普通鍵盤佈局的遊戲就不能運行。


圖2、 Nokia 3510i (左圖)原裝外殼 (右圖)遊戲外殼

  4 同時按鍵

   許多Nokia手機(例如,諾基亞6310i、3410、7210)不支持同時按下多鍵(也就是說,如果你按住Up鍵,那麼MIDlet就不會知道你是 否你按下Fire鍵)。雖然Nokia 7650支持同時按下多鍵(例如同時按住"1"和"3"鍵),但是操縱桿鍵物理上是無法同時又向左按又向上按的,所以在遊戲中不可能有斜向的運動,並且在 它被向上、向下、向左或者向右按下的時候是不能記錄一個"點擊"的。

  5 鍵名:避免硬編碼你自己的文本字符串

  避免把硬編碼文本和你的MIDlet中的鍵盤代碼相關聯。Canvas類提供了一個返回每個鍵盤代碼關聯的文本名稱的方法:

public static String getKeyName(int keyCode);

   現在的Nokia設備的問題是這個方法始終返回一個英語字符串,而不是根據用戶的語言選擇。在未來的Nokia設備中,這個字符串可能會基於用戶的語言 選擇。如果你的目的是開發可移植的遊戲,那麼必須記住getKeyName在不同的Nokia MIDP設備中返回不同的值。

  6 使用全屏畫布(FullCanvas)功能鍵

  一個基於全屏畫布(FullCanvas)遊戲屏幕的功能鍵只能用於從遊戲屏幕退出到不同的屏幕狀態。帶有FullCanvas類的Nokia用戶界面應用編程接口明確地提供一個全屏圖形區域用於繪圖,可用於許多類型的遊戲。

  繼承於Nokia用戶界面應用編程接口類FullCanvas的遊戲屏幕將不會把功能鍵的鍵盤代碼(即KEY_SOFTKEY1、KEY_SOFTKEY2,KEY_SOFTKEY3)用做遊戲相關的動作,除非是用於從遊戲屏幕返回到菜單中。

  如果一個MIDlet應用程序需要使用功能鍵命令,那麼你必須使用默認的MIDP Canvas類,特別是如果你的MIDlet需要使用標籤功能鍵的時候。當你使用FullCanvas的時候,你不應該提供你自己的功能鍵標籤。

  7 MIDlet國際化

   你有可能需要把你的MIDlet國際化--例如,用於不同的地區和語言。MIDP的系統屬性"microedition.locale"定義了設備的當 前區域。它的值可以使用System.getProperty.方法取得。MIDP規範允許在這個系統屬性中使用一個空值。然而,在Nokia的MIDP 實現中是不允許空值的。CLDC的系統屬性"microedition.encoding"定義了設備的默認字符編碼。它的值可以使用 System.getProperty方法取得。
想要了解更多MIDlet本地化問題,可以參閱《Writing World Aware J2ME Applications》http://wireless.java.sun.com/midp/ttips/worldaware/ 的資源包。目前在MIDP中還沒有一個標準機制用來處理資源包。這個文檔使用一種簡單的途徑把用戶界面文本從主程序中分離出來。它在Resource 類(二、9節)中被處理。

  把國際化特色加入一個MIDlet非常重要,但是這可能會增加你的MIDlet的大小。如果MIDlet大小對於某種特定MIDP設備來說是一個問題,那麼你可能希望產生好幾個不同編譯版本的MIDlet。每個版本可以爲一個或多個區域、語言本地化。

  8 設備特性:聲音、振動和燈光

  如果你使用Nokia用戶界面應用編程接口類Sound或DeviceControl(振動、燈光),你應該提供一個Options或Settings菜單和一個設置編輯器,來允許最終用戶啓動或者取消這樣的設置。

   然而,如果你使用Nokia用戶界面應用編程接口類Sound或DeviceControl(振動、燈光)並且通過設置JAD參數<>來把 你的遊戲安裝到Games菜單(見一、11節),Games菜單中已經提供的設置允許最終用戶啓動或者取消這些特性。因此應用程序沒有必要自己創建這樣一 個特性。除Nokia UI API技術文檔之外,你還可以參考《Nokia UI API Programmer ' s Guide》,它能提供很多有用的信息。

  9 設備無關性

  Nokia MIDP設備可能在屏幕尺寸、鍵盤佈局和可用API等方面不同。爲了創建可移植的遊戲,在設計遊戲時,這些差異應當被考慮在內。

  應用程序應該向系統詢問屏幕的尺寸,並且避免繪製屏幕內容的時候硬編碼座標。可以使用Canvas類的getHeight和getWidth方法來達到這個目的。

  不同的Nokia MIDP設備中應用編程接口變化很大,開發者應該檢查所要開發的設備平臺上的應用編程接口。這是可以做到的,振動就是一個很好的例子。

try{
Class.forName("com.nokia.mid.ui.DeviceControl");
}
catch(ClassNotFoundException e){
//Can't use vibration because the API
//is not supported in the device
}

  使用繼承於默認MIDP Canvas類的遊戲屏幕代替廠商特定的FullCanvas類,這有助於提高你的MIDlet的可移植性;然而,那就不可能實現全屏幕了。

  10 最優化

   MIDP設備的內存非常有限,所以使用內存時應格外小心。對於遊戲來說一個很重要的限制就是有限的堆內存(heap memory):爲了節省堆內存,對象引用不再需要被設置爲"null",以便這些對象可被垃圾-收集(garbage-collected)。彩屏手機 需要更多的內存來處理應用程序中的位圖,這與更大的屏幕位深度和相關的內部數據結構有關。因此,雖然一個應用程序可能編寫來使用在一個黑白屏幕的手機上, 但是在彩屏手機上使用時,它可能消耗更多動態內存:就Nokia 7210來說,它顯示一幅圖片時比Nokia 6310i多用16倍的內存。
開發者應該在設計應用程序時考慮到這個因素,應該把同時加載的圖片數降到最少的程度。例如,閃動屏幕圖像應該能夠在遊戲圖形圖象創建之前被垃圾收集(通過設置所有到圖像對象的引用爲"null")。

  11 安裝

  默認情況下MIDlet被安裝到Nokia設備的Applications菜單下。如果設備有Games菜單的話,MIDlet還可以通過設置MIDlet的.jad文件中的Nokia-MIDlet-Category:Game參數來安裝到這個菜單下。

  二、實現遊戲的步驟

  下圖顯示的是一個遊戲MIDlet在成功安裝和運行之後用戶界面狀態的典型的變化流程。我們想通過一個遊戲者的視角來闡述開發移動遊戲的過程。


圖3 用戶界面狀態圖表

  1 開始遊戲

   在用戶啓動MIDlet之後,將顯示遊戲特定的閃動屏幕。閃動屏幕是FullCanvas的一個實例。它可用於顯示一個公司的標誌或者用動畫形式介紹遊 戲。除了End鍵以外的所有鍵盤事件(MIDlet可用的)都可以跳過閃動屏幕並顯示主菜單。還應該設置一個時間限定,能夠在一定的時間過後自動跳出閃動 屏幕進入遊戲屏幕。
GameMIDlet類是遊戲的基本類;它處理MIDlet的生命週期並且處理遊戲顯示。下面的代碼是閃動屏幕和遊戲MIDlet類的構架。

//Skeleton for the base class of game
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class GameMIDlet extends MIDlet {
 private Display display = null;
 //Splash screen that starts the application
 private SplashFullCanvas splash;
 public GameMIDlet() {
  splash = new SplashFullCanvas(this);
 }
 protected void startApp() throws MIDletStateChangeException {
  if (display == null) {
   display = Display.getDisplay(this);
  }
  //splash screen to the display
  setDisplayable(splash);
 }
 protected void pauseApp() {
}

 protected void destroyApp(boolean p0)
 throws MIDletStateChangeException {
 }

 public void setDisplayable(Displayable dl) {
  display.setCurrent(dl);
 }
}

//Skeleton for the splash screen in Nokia Java Game
import javax.microedition.lcdui.*;
import java.util.Timer;
import java.util.TimerTask;
import com.nokia.mid.ui.*;

public class SplashFullCanvas extends FullCanvas {
 private GameMIDlet parent = null;
 private MainMenu menu = null;
 private Timer timer = null;
 public SplashFullCanvas(GameMIDlet parent) {
  this.parent = parent;
  menu = new MainMenu(
   Resources.getString(Resources.ID_GAME_NAME),
   List.IMPLICIT, parent);
   startTimer();
 }
protected void paint(Graphics g) {
 //Do the splash screen here
}
protected void keyPressed(int keyCode) {
 timer.cancel();
 timer = null;
 //All key events received set the main menu to the screen
 parent.setDisplayable(menu);
}

//Timer for the splash screen. Main menu is set to the display
//after 5 seconds.
private void startTimer() {
 TimerTask task =new TimerTask() {
  public void run() {
   parent.setDisplayable(menu);
  }
 };
 timer = new Timer();
 timer.schedule(task, 5000);
}
}

  2 主菜單(MainMenu)屏幕

   主菜單是包含遊戲特定選項的固有目錄("Continue"、"New game"、"Options"、"High scores"、"Instructions"、"About"和"Exit game")。"Continue"只有在遊戲被暫停的時候才能被顯示。當"Continue"顯示的時候,它必須是目錄列表的第一個元素。主菜單的標題 必須是遊戲的名稱。下面的代碼是主菜單的框架。

//Skeleton for the main menu
import javax.microedition.lcdui.*;
public class MainMenu extends List implements CommandListener {
 private GameMIDlet parent = null;
 private GameFullCanvas game = null;
 public MainMenu(String p0, int p1, String[] p2, Image[] p3,
 GameMIDlet parent) {
  super(p0, p1, p2, p3);
  init(parent);
 }
 public MainMenu(String p0, int p1, GameMIDlet parent) {
  super(p0, p1);
  init(parent);
 }
 public void init(GameMIDlet parent) {
  this.parent = parent;
  this.setCommandListener(this);
  //if game paused then "Continue" should be available in
  //selection list
  if (game != null && game.isPaused()) {
   if(!(this.getString(0).equals(
    new String(Resources.getString(
     Resources.ID_GAME_CONTINUE))))) {
      this.insert(0,
       Resources.getString(Resources.ID_GAME_CONTINUE),
       null);
     }
     this.setSelectedIndex(0,true);
    }
   else {
    //These must be with or without icons
    this.append(Resources.getString(Resources.ID_GAME_NEW), null);
    this.append(Resources.getString(Resources.ID_GAME_OPTIONS),null);
    this.append(Resources.getString(
     Resources.ID_GAME_HIGHSCORES), null);
    this.append(Resources.getString(
    Resources.ID_GAME_INSTRUCTIONS), null);
    this.append(Resources.getString(Resources.ID_GAME_ABOUT), null);
    this.append(Resources.getString(Resources.ID_GAME_EXIT), null);
   }
  }
  public void commandAction(Command p0, Displayable p1) {
   List lis = (List) p1;
   String selected =
   lis.getString(lis.getSelectedIndex());
   if (selected.equals(Resources.getString(Resources.ID_GAME_NEW))) {
    game = new GameFullCanvas(parent, this);
    parent.setDisplayable(game);
   }
   else if (selected.equals(
    Resources.getString(Resources.ID_GAME_OPTIONS))) {
     parent.setDisplayable(
      new OptionList(Resources.getString(Resources.ID_GAME_OPTIONS),
       List.IMPLICIT,
       parent, this));
    }
   else if (selected.equals(
    Resources.getString(Resources.ID_GAME_HIGHSCORES))) {
     parent.setDisplayable(new HighScore(parent, this));
    }
   else if (selected.equals(
    Resources.getString(Resources.ID_GAME_INSTRUCTIONS))) {
     parent.setDisplayable(
      new Instructions(
       Resources.getString(Resources.ID_GAME_INSTRUCTIONS),parent,this));
    }
   else if (selected.equals(
    Resources.getString(Resources.ID_GAME_ABOUT))) {
     parent.setDisplayable(
      new About(
       Resources.getString(Resources.ID_GAME_ABOUT),
       parent,
       this));
    }
   else if (selected.equals(
    Resources.getString(Resources.ID_GAME_EXIT))) {
     parent.notifyDestroyed();
   }
   else if (selected.equals(
    Resources.getString(Resources.ID_GAME_CONTINUE))) {
     if (game != null) {
      game.gameContinue();
      parent.setDisplayable(game);
   }
  }
 }
}
3 遊戲屏幕

  如果用戶從主菜單中選擇"New game",那麼開始遊戲並且顯示遊戲屏幕。遊戲屏幕使用全屏畫布(FullCanvas)。如果按下任何功能鍵,那麼用戶界面必須返回主菜單,並且應使 遊戲暫停。其他的按鍵對遊戲是有效的。注意:遊戲不應該在屏幕上創建任何功能鍵的標籤。如果必須使用功能鍵標籤,那麼應用程序應該使用默認的Canvas 屏幕Commands。示例代碼沒有解決諸如線程和線程安全等問題,這些問題在設計的時候必須格外注意。下面的代碼是遊戲屏幕的框架。

import javax.microedition.lcdui.*;
import com.nokia.mid.ui.*;
public class GameFullCanvas extends FullCanvas {
private GameMIDlet parent = null;
private MainMenu menu = null;
private boolean gamePaused = false;
public GameFullCanvas(GameMIDlet parent, MainMenu menu) {
this.parent = parent;
this.menu = menu;
}
protected void paint(Graphics g) {
//Paint the game screen here
}
protected void keyPressed(int keyCode) {
if (keyCode == KEY_SOFTKEY1 || keyCode == KEY_SOFTKEY2
|| keyCode == KEY_SOFTKEY3) {
gamePaused = true;
//main menu to the screen
menu.init(parent);
parent.setDisplayable(menu);
}
}
public void gameContinue() {
gamePaused = false;
}
public boolean isPaused() {
return gamePaused;
}
}

  4 遊戲選項屏幕

  用戶可以通過選擇主菜單中的"Options"選項改變特定的遊戲選項。Options列表是固有的列表,包含處理遊戲設置的條目,例如:聲音、振動(見一、8節)、音調等等。如果要回到主菜單的話,需要使用Back命令。下面的代碼是Options列表的框架。

  注意:如果遊戲被安裝到Games菜單的話,就不需要lights/sounds設置條目了,因爲那些選項已經由Games菜單提供了。

import javax.microedition.lcdui.*;
public class OptionList extends List implements CommandListener {
private GameMIDlet parent = null;
private MainMenu menu = null;
private KeyDefinitions def = null;
private Command back = new Command("", Command.BACK, 2);
public OptionList(String p0, int p1, String[] p2, Image[] p3,
GameMIDlet parent, MainMenu menu) {
super(p0, p1, p2, p3);
this.menu = menu;
init(parent);
}
public OptionList(String p0, int p1, GameMIDlet parent,
MainMenu menu) {
super(p0, p1);
this.menu = menu;
init(parent);
}
private void init(GameMIDlet parent) {
this.parent = parent;
this.addCommand(back);
this.setCommandListener(this);
//These are just a examples for the game specific options
this.append(Resources.getString(Resources.ID_GAME_LEVEL),
null);
this.append(Resources.getString(Resources.ID_GAME_SOUNDS),
null);
this.append(Resources.getString(Resources.ID_GAME_VIBRA),
null);
}
public void commandAction(Command p0, Displayable p1) {
if (p0 == back) {
parent.setDisplayable(menu);
}
else {
List lis = (List) p1;
int idx = lis.getSelectedIndex();
switch (idx) {
case 0:
//TODO
break;
case 1:
//TODO
break;
case 2:
//TODO
break;
case 3:
parent.setDisplayable(def);
break;
//More if needed
default:
break;
}
}
}
}
  5 高分屏幕

  當用戶從主菜單中選擇"High scores"選項的時候,高分就會顯示出來。高分是顯示在全屏畫布(FullCanvas)實例上的。分數應該在一個屏幕上就顯示完,而不要捲動頁面,因爲這樣會給用戶帶來麻煩。
當 然了,高分屏幕也可能會包含一些圖片或者動畫。用戶應該能夠通過按下左功能鍵、右功能鍵、數字鍵或者Send鍵返回主菜單。這個例子不提供任何處理高分的 機制。處理高分的兩種典型的方法是通過使用記錄管理服務(RMS)永久保存分數或者通過HTTP連接把高分保存到服務器中。下面的代碼是高分的框架。

import javax.microedition.lcdui.*;
import com.nokia.mid.ui.*;
public class HighScore extends FullCanvas {
private GameMIDlet parent = null;
private MainMenu menu = null;
public HighScore(GameMIDlet parent, MainMenu menu) {
this.parent = parent;
this.menu = menu;
}
protected void paint(Graphics g) {
//Paint the high scores here
}
public void keyPressed(int keyCode) {
if (keyCode != KEY_END) {
//selection list to the screen
parent.setDisplayable(menu);
}
}
}

  6 教學屏幕

   當用戶從主菜單中選擇"Instructions"條目的時候,就會顯示出遊戲的規則。遊戲規則文本放置在Form實例中。Form中應該包含用於進入 下一條教學規則的命令(例如,標籤"More")和回到主菜單的命令(例如,標籤"Back")。"More"一般由左功能鍵控制,而"Back"由右功 能鍵控制。如果教學規則裏包含動畫,那麼這些動畫應該使用全屏畫布(FullCanvas)來顯示。按下左功能鍵將跳過動畫進入下一個教學屏幕。按下右功 能鍵,用戶將從動畫中回到主菜單。鍵End將結束應用程序。下面的代碼是文字教學規則和動畫的框架。

//Text instructions. Text can be written in constructor or in own
method.
//Developer should remember that also instruction texts should be
//internationalized
import javax.microedition.lcdui.*;
public class Instructions extends Form implements CommandListener {
//Command for going next instruction if needed
private Command more = new Command(
Resources.getString(Resources.ID_GAME_MORE),
Command.OK, 1);
//Command for going back to the main menu
private Command back = new Command("", Command.BACK, 2);
private GameMIDlet parent = null;
private MainMenu menu = null;
public Instructions(String title, GameMIDlet parent, MainMenu
menu) {
super(title);
this.parent = parent;
this.menu = menu;
this.addCommand(back);
this.addCommand(more);
this.setCommandListener(this);
}
public void commandAction(Command p0, Displayable p1) {
if (p0 == more) {
//go to the next if needed e.g animation
parent.setDisplayable(new InstructionAnimation(parent));
}
else if (p0 == back) {
parent.setDisplayable(menu);
}
}
}
//Instruction animation
import javax.microedition.lcdui.*;
import com.nokia.mid.ui.*;
public class InstructionAnimation extends FullCanvas {
private GameMIDlet parent = null;
public InstructionAnimation(GameMIDlet parent) {
this.parent = parent;
}
protected void paint(Graphics g) {
//Do the animation here
}
public void keyPressed(int keyCode) {
if (keyCode == KEY_SOFTKEY1) {
//go to the next instruction screen if needed
}
else if (keyCode == KEY_SOFTKEY2) {
//selection list to the screen
parent.setDisplayable(new MainMenu(
Resources.getString (
Resources.ID_GAME_NAME),
List.IMPLICIT, parent));
}
}
}

  7關於(About)屏幕

   關於(About)屏幕顯示遊戲製作公司的消息文本或標誌。當用戶從主菜單中選擇"About"選項的時候,就會啓動這個屏幕。和教學規則頁面一樣,關 於屏幕頁面如果只需要文本信息的話,那麼可以使用Form來實現。如果需要圖像或動畫,那麼應該使用Canvas或FullCanvas。

//Text "About" code skeleton
import javax.microedition.lcdui.*;
public class About extends Form implements CommandListener {
//Command for going back to the main menu
private Command back = new Command("", Command.BACK, 1);
private GameMIDlet parent = null;
private MainMenu menu = null;
public About(String title, GameMIDlet parent, MainMenu menu) {
super(title);
this.parent = parent;
this.menu = menu;
this.addCommand(back);
this.setCommandListener(this);
}
public void commandAction(Command p0, Displayable p1) {
if (p0 == back) {
parent.setDisplayable(menu);
}
}
}

  8 退出

  從主菜單中選擇"Exit game"選項來中止遊戲並釋放所有的資源。

  9 Resources類

  Resources類不是一個用戶界面類,與本文中介紹的其他類不同。這個類處理國際化問題。

/**
* A simple class to simulate a resource bundle.
* Modify the contents of this class according to the
* locales/languages you want your application to support.
* In your application, retrieve a string using code such as the
* following:
* <pre>
* <code>String s = Resources.getString(Resources.ID_GAME_NEW);
* </code></pre>
* Copyright (C) 2002 Nokia Corporation
*/
public class Resources {
// Identifiers for text strings.
public static final int ID_GAME_NEW = 0;
public static final int ID_GAME_OPTIONS = 1;
public static final int ID_GAME_HIGHSCORES = 2;
public static final int ID_GAME_INSTRUCTIONS = 3;
public static final int ID_GAME_ABOUT = 4;
public static final int ID_GAME_CONTINUE = 5;
public static final int ID_GAME_BACK = 6;
public static final int ID_GAME_MORE = 7;
public static final int ID_GAME_EXIT = 8;
public static final int ID_GAME_LEVEL = 9;
public static final int ID_GAME_SOUNDS = 10;
public static final int ID_GAME_VIBRA = 11;
public static final int ID_GAME_NAME = 12;
// List of supported locales.
// The strings are Nokia-specific values
// of the "microedition.locale" system property.
private static final String[] supportedLocales = {
"en", "fi-FI", "fr", "de"
};
//NOTE: default language must be the first one
//for getString to work!
// Strings for each locale, indexed according to the
// contents of supportedLocales
private static final String[][] strings = {
{ "New game", "Settings", "High scores", "Instructions",
"About","Continue", "Back", "More", "Exit game",
"Level", "Sounds","Shakes", "Game name" },
{ "Uusi peli", "Asetukset", "Huipputulokset", "Peliohjeet",
"Tietoja","Jatka", "Poistu", "Jatka", "Poistu",
"Vaikeusaste", "Peli??net", "V?rin?tehosteet",
"Pelin nimi" },
{ "Nouveau jeu", "Paramètres", "Scores", "Instructions",
"A propos","Continuer", "Retour", "Suite", "Sortir",
"Niveau", "Sons", "Vibrations", "Jeu nom" },
{ "Neues Spiel", "Einstellungen", "Rekord", "Anleitung",
"über","Weiter", "Zurück", "Weiter", "Beenden",
"Ebene", "Ton", "Vibrationen", "Spiel name" }
};
/**
* Gets a string for the given key.
* @param key Integer key for string
* @return The string
*/
public static String getString(int key) {
String locale = System.getProperty("microedition.locale");
if (locale == null) {
locale = new String(""); // use empty instead of null
}
// find the index of the locale id
int localeIndex = -1;
for (int i = 0; i < supportedLocales.length; i++) {
if (locale.equals(supportedLocales[i])) {
localeIndex = i;
break;
}
}
// not found
if (localeIndex == -1) {
// defaults to first language, in this example English
return strings[0][key];
}
return strings[localeIndex][key];
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章