<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    游戲策劃咨訊
    做一個(gè)游戲并不難,難的是做一個(gè)好游戲;完美在于積累!

    本文通過(guò)一個(gè)簡(jiǎn)單的MIDlet游戲程序示例,簡(jiǎn)要介紹了MIDlet圖形編程.....

    介紹

      本文通過(guò)一個(gè)簡(jiǎn)單的MIDlet游戲程序示例,簡(jiǎn)要介紹了MIDlet圖形編程,以期能對(duì)開(kāi)發(fā)者深入理解MIDP圖形編程和開(kāi)發(fā)復(fù)雜的移動(dòng)游戲有所幫助。

      一. MIDLET圖形

      1、MIDlet 圖形簡(jiǎn)述

      移動(dòng)信息設(shè)備描述(Mobile Information Device Profile ,MIDP)定義了一套應(yīng)用編程接口(API),用于運(yùn)行在MIDP容器中的MIDlet應(yīng)用程序。這套API本身是建立在有限連接設(shè)備配置(Connected Limited Device Configuration ,CLDC)應(yīng)用編程接口的基礎(chǔ)上的。MIDP用戶界面應(yīng)用編程接口類并不是基于Java抽象窗口工具包(Abstract Window Toolkit ,AWT)設(shè)計(jì)。它們是專為手機(jī)和呼機(jī)這樣的小型移動(dòng)信息設(shè)備而設(shè)計(jì)的,這類設(shè)備的特點(diǎn)是只有很小的屏幕和鍵盤(pán)。當(dāng)一個(gè)程序員在編寫(xiě)MIDP圖形應(yīng)用程序的時(shí)候,他可能只能使用MIDP或CLDC應(yīng)用編程接口。

      MIDP的中心抽象是屏幕,這句話的含義是MIDP的用戶界面設(shè)計(jì)是基于屏幕的(screen-based)。也就是說(shuō),Screen類封裝了設(shè)備特定的圖形和用戶交互,所有的用戶界面組件都位于屏幕上,并且一次只顯示一個(gè)屏幕,并且只能瀏覽或使用這個(gè)屏幕上的條目。由屏幕來(lái)處理所有的用戶界面事件。并只把高級(jí)事件傳送給應(yīng)用。之所以采取這種面向屏幕(screen-oriented) 的方式,主要是因?yàn)橐苿?dòng)設(shè)備的顯示屏幕和鍵盤(pán)實(shí)是種類太多了,幾乎每個(gè)廠家都多多少少有所不同。圖1是基于屏幕的MIDP圖形用戶界面的一些例子。


    圖1:基于屏幕的MIDP 圖形用戶界面

      MIDP 應(yīng)用編程接口具有高級(jí)用戶界面類和低級(jí)用戶界面類。高級(jí)用戶界面類(例如Form、List、TextBox、TextField、Alert,及Ticker)可被適配到設(shè)備上:支持圖像、文本、文本輸入域、單選按鈕等。低級(jí)用戶界面類(Canvas類)允許開(kāi)發(fā)者根據(jù)需要繪制任意圖形。MIDlet可以運(yùn)行在各種不同尺寸的彩色、不同灰度等級(jí)或黑白屏幕的手機(jī)上。高級(jí)用戶界面類是通用用戶界面元素的抽象,它的用途在于提高M(jìn)IDlet跨不同設(shè)備的移植性,并且可以使用本地設(shè)備的外觀表現(xiàn)。低級(jí)應(yīng)用編程接口則能夠更直接地控制顯示內(nèi)容,但是MIDlet設(shè)計(jì)者應(yīng)該確保其在不同設(shè)備(顯示尺寸、鍵盤(pán)、色彩等)上的可移植性。上面的例子既用到了高級(jí)應(yīng)用編程接口又用到了低級(jí)應(yīng)用編程接口。

      所有的MIDP圖形用戶界面類都是javax.microedition.lcdui程序包的一部分。

      2、MIDlet屏幕

      MIDP有兩種主要的屏幕類型:

      A 高級(jí)屏幕

       它包括簡(jiǎn)單的高級(jí)屏幕類,例如List和TextBox。用戶不能添加額外的圖形用戶界面組件到這種類型的屏幕中。九宮格MIDlet示例程序使用的屏幕是繼承于名為ChoosePieceScreen的List類,用于游戲者在游戲開(kāi)始時(shí)選擇棋子。

       一般的Form屏幕類和List類很相像,但是它允許使用額外的圖形元素,例如:圖像、只讀文本域、可編輯文本域、可編輯數(shù)據(jù)域、標(biāo)尺和選項(xiàng)組。Form條目可以任意地被添加或刪除。九宮格例程中沒(méi)有使用Form類。

      B 低級(jí)屏幕

       Canvas(畫(huà)布)屏幕(和Graphics、Image類) 可以用來(lái)編寫(xiě)基于低級(jí)應(yīng)用編程接口的用戶界面。這些類給予MIDlet程序員很大程度的繪畫(huà)靈活性。程序員可以繪制各種類型的圖形元素,例如:線、弧、矩形、圓角矩形、圓、文字(不同顏色、字體、大小)、位圖剪輯等等。大部分的游戲MIDlet是使用基于畫(huà)布屏幕類的主圖形用戶界面元素編寫(xiě)的。

      一個(gè)MIDlet用戶界面通常包含一個(gè)或多個(gè)屏幕。因?yàn)槊看沃荒茱@示一個(gè)屏幕,因此MIDlet具有良好設(shè)計(jì)的結(jié)構(gòu)是非常重要的進(jìn)行,這樣就能更加容易地處理屏幕之間內(nèi)容的切換。

      下面的代碼段說(shuō)明了在一個(gè)MIDlet中切換屏幕的方法,基于屏幕類和對(duì)應(yīng)的MIDlet回調(diào)。

      代碼段1:

    Class MyMIDlet extends MIDlet
    {
    private FirstScreen firstScreen;
    private SecondScreen secondScreen;
    public MyMIDlet()
    {

    }
    public void startApp()
    {
    Displayable current = Display.getDisplay(this).getCurrent();
    if (current == null)
    {
    firstScreen = new FirstScreen(this, …);
    Display.getDisplay(this).setCurrent(firstScreen);
    //顯示應(yīng)用程序的第一個(gè)用戶界面屏幕
    }
    else
    {
    Display.getDisplay(this).setCurrent(current);
    }
    }
    // FirstScreen 回調(diào)切換到下一個(gè)屏幕
    public void firstScreenDone()
    {

    secondScreen = new SecondScreen(this, …);
    display.getDisplay(this).setCurrent(secondScreen);
    }
    // SecondScreen回調(diào)終止應(yīng)用程序
    public void secondScreenQuit()
    {

    destroyApp(false);
    notifyDestroyed();
    }

    }


      這個(gè)MIDlet使用了兩個(gè)屏幕類(FirstScreen和SecondScreen)作為用戶界面。當(dāng)開(kāi)始執(zhí)行MIDlet的時(shí)候,它設(shè)置當(dāng)前顯示屏幕為FirstScreen。當(dāng)需要從FirstScreen切換到SecondScreen的時(shí)候,F(xiàn)irstScreen 調(diào)用父MIDlet方法firstScreenDone(參見(jiàn)下面的代碼)。firstScreenDone方法創(chuàng)建并設(shè)置SecondScreen為當(dāng)前顯示的屏幕。

      代碼段2: 包含MIDlet回調(diào)的FirstScreen示例

    Class FirstScreen extends Form implements CommandListener {
    private MyMIDlet midlet;
    public FirstScreen(MyMIDlet midlet)
    {
    this.midlet = midlet;

    }
    public void commandAction(Command c)
    {
    if (c == cmdQuit)
    {
    parent.firstScreenDone();
    }

    }

    }


      3、MIDP用戶界面應(yīng)用編程接口

      保證基于高級(jí)應(yīng)用編程接口類的用戶界面對(duì)象的可移植性和適用性是MIDP設(shè)備的職責(zé)。

      另一方面,像Canvas和Graphics這樣的低級(jí)類為程序員提供了更大的自由空間讓其控制其用戶界面的視覺(jué)表現(xiàn),并且監(jiān)聽(tīng)低級(jí)鍵盤(pán)事件。程序員還要負(fù)責(zé)確保應(yīng)用程序在不同特性(例如顯示尺寸、彩色或黑白,以及不同鍵盤(pán)類型)的移動(dòng)設(shè)備上的可移植性。比如說(shuō),有可能需要使用getWidth()和getHeight()方法調(diào)節(jié)用戶界面外觀使其適應(yīng)一個(gè)或更多設(shè)備的可用Canvas尺寸。

      下面的九宮格MIDlet例程將介紹:

       簡(jiǎn)單應(yīng)用高級(jí)應(yīng)用編程接口;

       使用低級(jí)應(yīng)用編程接口來(lái)繪制線、弧、字符串和圖像等圖形;

       不同顯示尺寸的移動(dòng)設(shè)備之間的MIDlet移植問(wèn)題

       鍵盤(pán)代碼與游戲動(dòng)作之間的映射

      本章概述了MIDP圖形用戶界面的設(shè)計(jì),如果想得到更進(jìn)一步的信息,請(qǐng)參閱
    http://java.sun.com/products/midp/ 。

      二. 示例:九宮格(TICTACTOEMIDLET)

      1、設(shè)計(jì)

      概述

      這個(gè)示例應(yīng)用程序是一個(gè)簡(jiǎn)單的MIDlet,允許游戲者與MIDlet程序之間玩一種稱為九宮格的人機(jī)游戲。這個(gè)例程說(shuō)明:

       使用高級(jí)和低級(jí)用戶界面組件

       在多顯示屏幕之間進(jìn)行切換

       處理簡(jiǎn)單的命令

       動(dòng)態(tài)適配顯示尺寸
     
       處理鍵盤(pán)事件

      游戲者首先選擇使用哪種棋子(用圓和叉表示),然后開(kāi)始游戲。游戲者和MIDlet誰(shuí)是先手是隨機(jī)決定的。每走一步棋之后,程序都要檢查游戲狀態(tài),判斷游戲是否已經(jīng)結(jié)束。游戲的幾種可能結(jié)果是:游戲者贏,MIDlet程序贏,或者平局。在應(yīng)用程序運(yùn)行期間,雙方的得分都能顯示出來(lái)。游戲者可以隨時(shí)開(kāi)始新游戲或者退出游戲。 

      圖2:所示的屏幕快照是游戲中的MIDlet用戶界面。


    圖2:游戲屏幕的先后順序

      2、九宮格MIDlet

      下面是九宮格MIDlet的類模式圖:


    圖3:九宮格MIDlet類圖

      當(dāng)MIDlet啟動(dòng)方法startApp()時(shí),將創(chuàng)建閃爍屏幕和第一個(gè)游戲屏幕(ChoosePieceScreen)。閃爍屏幕顯示4秒之后,第一個(gè)游戲屏幕開(kāi)始顯示。ChoosePieceScreen讓游戲者選擇使用哪種棋子(圓還是叉)。當(dāng)游戲者做出選擇之后,他可以使用OK鍵確認(rèn)。這會(huì)使ChoosePieceScreen回調(diào)主MIDlet的choicePieceScreenDone()方法。

      ChoosePieceScreen是使用高級(jí)應(yīng)用編程接口List類實(shí)現(xiàn)的。 

     
    圖4:ChoosePieceScreen是一個(gè)高級(jí)用戶界面List子類

      choosePieceScreenDone()回調(diào)創(chuàng)建并顯示下一個(gè)屏幕,這個(gè)屏幕在此應(yīng)用程序中作為游戲的主屏(GameScreen)。

      每當(dāng)輪到游戲者下棋的時(shí)候,游戲者使用GameScreen的箭頭鍵和Select按鈕來(lái)選擇想要走的空格。每一回合之后,應(yīng)用程序都會(huì)檢查游戲的狀態(tài),檢查其是否符合游戲結(jié)束條件并顯示游戲結(jié)果。游戲者通過(guò)點(diǎn)擊GameScreen的Quit命令結(jié)束游戲,或使用New命令開(kāi)始新一輪游戲。Quit(結(jié)束)命令調(diào)用TicTacToeMIDlet的quit()方法,然后MIDlet就會(huì)調(diào)用destroyApp()方法來(lái)終止整個(gè)MIDlet程序。

      游戲程序邏輯被封裝在一個(gè)單獨(dú)的Game類中。本文只關(guān)注MIDlet的圖形設(shè)計(jì),而對(duì)游戲程序邏輯不作深入探討。如果要與現(xiàn)有的applet Java程序作比較,請(qǐng)參閱http://java.sun.com/applets/jdk/1.0/demo/TicTacToe/TicTacToe.java 和http://java.sun.com/products/jfc/tsc/articles/tictactoe/index.html 中的游戲程序邏輯。
    GameScreen通過(guò)使用低級(jí)Canvas和Graphics類來(lái)實(shí)現(xiàn)。它使用Canvas、Image和Graphics對(duì)象來(lái)繪制圖形。
    GameScreen首先初始化基于畫(huà)布尺寸的顯示面板。這可讓MIDlet能夠運(yùn)行在不同顯示屏幕的移動(dòng)設(shè)備上。在本例中還使用了一個(gè)Image對(duì)象用來(lái)表示游戲面板。然后GameScreen根據(jù)游戲者在ChoosePieceScreen中所做的選擇為游戲者和MIDlet分配棋子。游戲然后進(jìn)行初始化(包括隨機(jī)決定誰(shuí)是先手),然后游戲就開(kāi)始了。
    為了使GameScreen能夠被移植,MIDlet的鍵盤(pán)代碼必須被映射到游戲動(dòng)作上,如:Up、Down、Left、Right和Fire,用于具有不同鍵盤(pán)的移動(dòng)設(shè)備。每當(dāng)一個(gè)鍵被按下的時(shí)候,keyPressed()方法就會(huì)判斷這是一個(gè)方向鍵還是一個(gè)Fire/Select鍵。如果按下的鍵是方向鍵,光標(biāo)就會(huì)相應(yīng)地移動(dòng),幫助游戲者可視化地選擇一個(gè)空格放入棋子。Select鍵用來(lái)選擇一個(gè)空格放入棋子。如果探測(cè)到滿足游戲結(jié)束的條件,就會(huì)顯示一條信息宣布游戲的獲勝者和本輪游戲的得分。(見(jiàn)下圖)

     
    圖5: GameScreen 是一個(gè)低級(jí) Canvas(畫(huà)布)子類

      3、TicTacToeMIDlet.java

      TicTacToeMIDlet非常簡(jiǎn)單:它處理MIDlet的生命周期事件。它根據(jù)需要?jiǎng)?chuàng)建屏幕對(duì)象并且處理來(lái)自屏幕的回調(diào)。ChoosePieceScreenDone回調(diào)被用來(lái)創(chuàng)建GameScreen。quit方法則被GameScreen用來(lái)結(jié)束游戲。

    package example.tictactoe;
    import java.io.IOException;
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    import javax.microedition.io.*;
    public class TicTacToeMIDlet extends MIDlet {
    private ChoosePieceScreen choosePieceScreen;
    private GameScreen gameScreen;
    public TicTacToeMIDlet()
    {
    }
    public void startApp() {
    Displayable current = Display.getDisplay(this).getCurrent();
    if (current == null) {
    // first time we've been called
    // Get the logo image
    Image logo = null;
    try
    {
    logo = Image.createImage("/tictactoe.png");
    }
    catch (IOException e) {
    // just use null image
    }
    Alert splashScreen = new Alert(null, "Tic-Tac-Toe\nForum Nokia", logo, AlertType.INFO);


    splashScreen.setTimeout(4000);
    // 4 seconds
    choosePieceScreen = new ChoosePieceScreen(this);
    Display.getDisplay(this).setCurrent(splashScreen, choosePieceScreen);
    }
    else
    {
    Display.getDisplay(this).setCurrent(current);
    }
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void quit()
    {
    destroyApp(false);
    notifyDestroyed();
    }
    public void choosePieceScreenDone(boolean isPlayerCircle)
    {
    gameScreen = new GameScreen(this, isPlayerCircle);
    Display.getDisplay(this).setCurrent(gameScreen);
    }
    }

      4、ChoosePieceScreen.java

      ChoosePieceScreen是一個(gè)基于高級(jí)應(yīng)用編程接口窗體的屏幕,允許游戲者選擇圓或叉作為棋子。當(dāng)游戲者按下OK鍵時(shí),它使用MIDlet的回調(diào)方法choosePieceScreenDone來(lái)處理游戲者的選擇。

    package example.tictactoe;
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    import javax.microedition.io.*;
    public class ChoosePieceScreen extends List implements CommandListener
    {
    private static final String CIRCLE_TEXT = "Circle";
    private static final String CROSS_TEXT = "Cross";
    private final TicTacToeMIDlet midlet;
    private final Command quitCommand;
    public ChoosePieceScreen(TicTacToeMIDlet midlet) {
    super("Choose your piece", List.IMPLICIT);
    this.midlet = midlet;
    append(CIRCLE_TEXT, loadImage("/circle.png"));
    append(CROSS_TEXT, loadImage("/cross.png"));
    quitCommand = new Command("Quit", Command.EXIT, 2);
    addCommand(quitCommand);
    setCommandListener(this);
    }
    public void commandAction(Command c, Displayable d) {
    boolean isPlayerCircle = getString(getSelectedIndex()).equals(CIRCLE_TEXT);
    if (c == List.SELECT_COMMAND) {
    midlet.choosePieceScreenDone(isPlayerCircle);
    }
    else
    // quit Command
    {
    midlet.quit();
    }
    }
    private Image loadImage(String imageFile)
    {
    Image image = null;
    try

    {
    image = Image.createImage(imageFile);
    }
    catch (Exception e)
    {
    // Use a 'null' image in the choice list (i.e. text only choices).
    }
    return image;
    }
    }

      5、GameScreen.java

      GameScreen使用了一個(gè)低級(jí)應(yīng)用編程接口Canvas屏幕,和Image、Graphics類來(lái)繪制游戲面板、棋子,以及游戲的最終結(jié)果狀態(tài)。要獲取更詳細(xì)的信息,請(qǐng)參閱各種繪畫(huà)方法和drawCircle、drawCross、drawPiece、drawPlayerCursor、drawBoard等方法。這個(gè)屏幕使用MIDlet的quit回調(diào)方法來(lái)指示游戲結(jié)束。
    此屏幕可適應(yīng)各種可用顯示性能(高、寬、色彩等)。此外還要注意到可以使用四向?qū)Ш芥I,也可以使用雙向?qū)Ш芥I來(lái)移動(dòng)光標(biāo)。

      它使用了封裝了主游戲程序邏輯的Game類。

    package example.tictactoe;
    import java.util.Random;
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    class GameScreen extends Canvas implements CommandListener {
    private static final int BLACK = 0x00000000;
    private static final int WHITE = 0x00FFFFFF;
    private static final int RED = 0x00FF0000;
    private static final int BLUE = 0x000000FF;
    private static final int NO_MOVE = -1;
    private final TicTacToeMIDlet midlet;
    private final Game game;
    private final Command exitCommand;
    private final Command newGameCommand;
    private final Random random = new Random();
    private int screenWidth, screenHeight;
    private int boardCellSize, boardSize, boardTop, boardLeft;
    private boolean playerIsCircle;
    private boolean computerIsCircle;
    private int preCursorPosition, cursorPosition;
    private int computerMove = NO_MOVE;
    private int playerMove = NO_MOVE;
    private int computerGamesWonTally = 0;
    private int playerGamesWonTally = 0;
    private boolean isRestart;
    public GameScreen(TicTacToeMIDlet midlet, boolean playerIsCircle) {
    this.midlet = midlet;
    this.playerIsCircle = playerIsCircle;
    computerIsCircle = !playerIsCircle;
    game = new Game(random);
    initializeBoard();
    // configure Screen commands
    exitCommand = new Command("Exit", Command.EXIT, 1);
    newGameCommand = new Command("New", Command.SCREEN, 2);
    addCommand(exitCommand);
    addCommand(newGameCommand);
    setCommandListener(this);
    // begin the game play initialize();
    }
    // Initialize the Game and Game screen. Also used for game restarts.
    private void initialize() {
    game.initialize();
    preCursorPosition = cursorPosition = 0;
    playerMove = NO_MOVE;
    boolean computerFirst = ((random.nextInt() & 1) == 0);
    if (computerFirst) {
    computerMove = game.makeComputerMove();
    }
    else
    {
    computerMove = NO_MOVE;
    }
    isRestart = true;
    repaint();
    }
    public void paint(Graphics g) {
    if (game.isGameOver()) {
    paintGameOver(g);
    }
    else {
    paintGame(g);
    }
    }
    private void paintGame(Graphics g) {
    if (isRestart) {
    // clean the canvas
    g.setColor(WHITE);
    g.fillRect(0, 0, screenWidth, screenHeight);
    drawBoard(g);
    isRestart = false;
    }
    drawCursor(g);
    if (playerMove != NO_MOVE) {
    drawPiece(g, playerIsCircle, playerMove);
    }
    if (computerMove != NO_MOVE) {
    drawPiece(g, computerIsCircle, computerMove);
    }
    }
    private void paintGameOver(Graphics g)

    {
    String statusMsg = null;
    if(game.isComputerWinner()) {
    statusMsg = "I win !";
    computerGamesWonTally++;
    }
    else if (game.isPlayerWinner()) {
    statusMsg = "You win";
    playerGamesWonTally++;
    }
    else {
    statusMsg = "Stalemate";
    }
    String tallyMsg = "You:" + playerGamesWonTally + " Me:" + computerGamesWonTally;
    Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
    int strHeight = font.getHeight();
    int statusMsgWidth = font.stringWidth(statusMsg);
    int tallyMsgWidth = font.stringWidth(tallyMsg);
    int strWidth = tallyMsgWidth;
    if (statusMsgWidth > tallyMsgWidth)
    {
    strWidth = statusMsgWidth;
    }
    // Get the
    {
    x, y
    }
    position for painting the strings. int x = (screenWidth - strWidth) / 2;
    x = x < 0 ? 0 : x;
    int y = (screenHeight - 2 * strHeight) / 2;
    y = y < 0 ? 0 : y;
    // clean the canvas
    g.setColor(WHITE);
    g.fillRect(0, 0, screenWidth, screenHeight);
    // paint the strings' text
    g.setColor(BLACK);
    g.drawString(statusMsg, x, y, (Graphics.TOP | Graphics.LEFT));
    g.drawString(tallyMsg, x, (y + 1 + strHeight), (Graphics.TOP | Graphics.LEFT));
    }


    public void commandAction(Command c, Displayable d) {
    if (c == exitCommand) {
    midlet.quit();
    }
    else if (c == newGameCommand) {
    initialize();
    }
    }
    private void initializeBoard() {
    screenWidth = getWidth();
    screenHeight = getHeight();
    if (screenWidth > screenHeight) {
    boardCellSize = (screenHeight - 2) / 3;
    boardLeft = (screenWidth - (boardCellSize * 3)) / 2;
    boardTop = 1;
    }
    else {
    boardCellSize = (screenWidth - 2) / 3;
    boardLeft = 1;
    boardTop = (screenHeight - boardCellSize * 3) / 2;
    }
    }
    protected void keyPressed(int keyCode) {
    // can't continue playing until the player restarts
    if (game.isGameOver()) {
    return;
    }
    int gameAction = getGameAction(keyCode);
    switch (gameAction) {
    case FIRE: doPlayerMove();


    break;
    case RIGHT: doMoveCursor(1, 0);
    break;
    case DOWN: doMoveCursor(0, 1);
    break;
    case LEFT: doMoveCursor(-1, 0);
    break;
    case UP: doMoveCursor(0, -1);
    break;
    default: break;
    }
    }
    private void doPlayerMove() {
    if (game.isFree(cursorPosition)) {
    // player move game.
    makePlayerMove(cursorPosition);
    playerMove = cursorPosition;
    // computer move
    if (!game.isGameOver()) {
    computerMove = game.makeComputerMove();
    }
    repaint();
    }
    }
    private void doMoveCursor(int dx, int dy) {
    int newCursorPosition = cursorPosition + dx + 3 * dy;
    if ((newCursorPosition >= 0) && (newCursorPosition < 9))

    {
    preCursorPosition = cursorPosition;
    cursorPosition = newCursorPosition;
    repaint();
    }
    }
    // Draw a CIRCLE or CROSS piece on the board
    private void drawPiece(Graphics g, boolean isCircle, int pos) {
    int x = ((pos % 3) * boardCellSize) + 3;
    int y = ((pos / 3) * boardCellSize) + 3;
    if (isCircle) {
    drawCircle(g, x, y);
    }
    else {
    drawCross(g, x, y);
    }
    }
    // Draw blue CIRCLE onto the board image
    private void drawCircle(Graphics g, int x, int y) {
    g.setColor(BLUE);
    g.fillArc(x + boardLeft, y + boardTop, boardCellSize - 4, boardCellSize - 4, 0, 360);
    g.setColor(WHITE);
    g.fillArc(x + 4 + boardLeft, y + 4 + boardTop, boardCellSize - 4 - 8, boardCellSize - 4 - 8, 0, 360);
    }
    // Draw red CROSS onto the board image
    private void drawCross(Graphics g, int x, int y) {
    g.setColor(RED);
    for (int i = 0;
    i < 4;
    i++) {
    g.drawLine(x + 1 + i + boardLeft, y + boardTop, x + boardCellSize - 4 - 4 + i + boardLeft, y + boardCellSize - 5 + boardTop);


    g.drawLine(x + 1 + i + boardLeft, y + boardCellSize - 5 + boardTop, x + boardCellSize - 4 - 4 + i + boardLeft, y + boardTop);
    }
    }
    // Visually indicates a Player selected square on the board image
    private void drawCursor(Graphics g) {
    // draw cursor at selected Player square.
    g.setColor(WHITE);
    g.drawRect(((preCursorPosition % 3) * boardCellSize) + 2 + boardLeft, ((preCursorPosition/3) * boardCellSize) + 2 + boardTop, boardCellSize - 3, boardCellSize - 3);
    // draw cursor at selected Player square.
    g.setColor(BLACK);
    g.drawRect(((cursorPosition % 3) * boardCellSize) + 2 + boardLeft, ((cursorPosition/3) * boardCellSize) + 2 + boardTop, boardCellSize - 3, boardCellSize - 3);
    }
    private void drawBoard(Graphics g) {
    // clean the board
    g.setColor(WHITE);
    g.fillRect(0, 0, screenWidth, screenHeight);
    // draw the board
    g.setColor(BLACK);
    for (int i = 0;
    i < 4;
    i++) {
    g.fillRect(boardLeft, boardCellSize * i + boardTop, (boardCellSize * 3) + 2, 2);
    g.fillRect(boardCellSize * i + boardLeft, boardTop, 2, boardCellSize * 3);
    }
    }
    }

      6、Game.java

      這個(gè)類封裝了九宮格游戲的主要的游戲程序邏輯。前面我們也說(shuō)過(guò),游戲程序邏輯本身并不在本例程重點(diǎn)討論的范圍之內(nèi),本文主要是介紹MIDP圖形編程的基礎(chǔ)知識(shí)。游戲程序邏輯的WINS數(shù)組部分來(lái)自http://java.sun.com/applets/jdk/1.0/demo/TicTacToe/TicTacToe.java 這個(gè)經(jīng)典例程。

      注意游戲程序邏輯是獨(dú)立于游戲用戶界面的(參見(jiàn)類GameScreen),并且可以使用其它實(shí)現(xiàn)方法替代。

    package example.tictactoe;
    import java.util.Random;
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    // The game logic for TicTacToe
    class Game {
    private static final int[] WINS = {
    // horizontals
    bit(0) | bit(1) | bit(2),
    bit(3) | bit(4) | bit(5),
    bit(6) | bit(7) | bit(8),
    // verticals
    bit(0) | bit(3) | bit(6),
    bit(1) | bit(4) | bit(7),
    bit(2) | bit(5) | bit(8),
    // diagonals
    bit(0) | bit(4) | bit(8),
    bit(2) | bit(4) | bit(6) }
    ;
    private static final int DRAWN_GAME = bit(0) | bit(1) | bit(2) | bit(3) | bit(4) | bit(5) | bit(6) | bit(7) | bit(8);
    private int playerState;
    private int computerState;
    private Random random;
    Game(Random random) {
    this.random = random;
    initialize();
    }
    void initialize() {
    playerState = 0;
    computerState = 0;
    }
    boolean isFree(int position) {
    int bit = bit(position);
    return (((playerState & bit) == 0) && ((computerState & bit) == 0));
    }
    // The 'Contract' is that caller will always make valid moves.
    // We don't check that it's the player's turn.
    void makePlayerMove(int position) {
    playerState |= bit(position);
    }
    // The 'Contract' is that we will be called only when there is still
    // at least one free square.
    int makeComputerMove() {
    int move = getWinningComputerMove();
    if (move == -1) {
    // can't win
    move = getRequiredBlockingComputerMove();
    if (move == -1) {
    // don't need to block
    move = getRandomComputerMove();
    }
    }
    computerState |= bit(move);
    return move;
    }


    boolean isGameOver() {
    return isPlayerWinner() | isComputerWinner() | isGameDrawn();
    }
    boolean isPlayerWinner() {
    return isWin(playerState);
    }
    boolean isComputerWinner() {
    return isWin(computerState);
    }
    boolean isGameDrawn() {
    return (playerState | computerState) == DRAWN_GAME;
    }
    // Return a winning move if there is at least one, otherwise return -1
    private int getWinningComputerMove() {
    int move = -1;
    for (int i = 0;
    i < 9;
    ++i) {
    if (isFree(i) && isWin(computerState | bit(i))) {
    move = i;
    break;
    }
    }
    return move;
    }
    // Return a required blocking move if there is at least one (more
    // than one and we've inevitably lost), otherwise return -1
    private int getRequiredBlockingComputerMove() {
    int move = -1;
    for (int i = 0;
    i < 9;
    ++i) {


    if (isFree(i) && isWin(playerState | bit(i))) {
    move = i;
    break;
    }
    }
    return move;
    }
    // Return a random move in a free square, // or return -1 if none are available private int getRandomComputerMove() {
    int move = -1;
    // determine how many possible moves there are int numFreeSquares = 0;
    for (int i = 0;
    i < 9;
    ++i) {
    if (isFree(i)) {
    numFreeSquares++;
    }
    }
    // if there is at least one possible move, pick randomly
    if (numFreeSquares > 0) {
    // shift twice to get rid of sign bit, then modulo numFreeSquares
    int pick = ((random.nextInt()<<1)>>>1) % numFreeSquares;
    // now find the chosen free square by counting pick down to zero
    for (int i = 0;
    i < 9;
    ++i) {
    if (isFree(i)) {
    if (pick == 0) {
    move = i;
    break;
    }
    pick--;
    }
    }
    }

    return move;
    }
    private static boolean isWin(int state) {
    boolean isWinner = false;
    for (int i = 0;
    i < WINS.length;
    ++i) {
    if ((state & WINS[i]) == WINS[i]) {
    isWinner = true;
    break;
    }
    }
    return isWinner;
    }
    private static int bit(int i) {
    return 1 << i;
    }
    }

      7、TicTacToe.jad

      下面是九宮格MIDlet的應(yīng)用程序描述文件。

    MIDlet-Name: TicTacToe
    MIDlet-Vendor: Forum Nokia MIDlet-Version: 1.1.1
    MIDlet-Jar-Size: 11409
    MIDlet-Jar-URL: TicTacToe.jar
    MIDlet-1: TicTacToe, /tictactoe.png, example.tictactoe.TicTacToeMIDlet

    posted on 2005-02-16 22:04 藍(lán)色雪焰 閱讀(208) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
     
    主站蜘蛛池模板: 青青草国产免费久久久91| 99久9在线|免费| 免费一级毛片在播放视频| 中文字幕亚洲情99在线| 亚洲欧洲免费无码| 亚洲日韩AV一区二区三区四区 | 久久亚洲AV午夜福利精品一区| caoporn国产精品免费| 国产成人亚洲精品影院| 亚欧国产一级在线免费| 亚洲热妇无码AV在线播放| 国产成人免费ā片在线观看老同学 | 国产精品亚洲高清一区二区| 国产精品内射视频免费| 亚洲乱码中文字幕久久孕妇黑人 | 99热亚洲色精品国产88| 日韩中文无码有码免费视频 | 99在线观看精品免费99| 亚洲日韩中文字幕| 免费无码成人AV片在线在线播放 | 成人性生交大片免费看好| 日木av无码专区亚洲av毛片| 亚洲一区二区免费视频| 456亚洲人成影院在线观| 亚洲?V无码成人精品区日韩| 999zyz**站免费毛片| 亚洲第一精品电影网| 成人免费无码大片A毛片抽搐| 在线观看亚洲精品专区| 亚洲欧洲美洲无码精品VA| 中国xxxxx高清免费看视频| 亚洲乱人伦中文字幕无码| 国产亚洲色视频在线| 中文字幕在线观看免费视频 | 亚洲国产成人精品无码久久久久久综合 | 青青草国产免费国产是公开| 亚洲综合精品香蕉久久网97| 日日夜夜精品免费视频| 国产情侣久久久久aⅴ免费| 亚洲一区二区三区写真| 亚洲精品国产精品乱码不99|