程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2ME >> 使用J2ME技術開發RPG游戲

使用J2ME技術開發RPG游戲

編輯:J2ME

RPG(角色扮演游戲)是手機游戲中的一類主要類型,也是相對來說比較麻煩的一類游戲,下面通過一系列的文章來介紹如何使用J2ME技術來開發RPG游戲。        首先讓我們來看一下游戲的骨架——程序框架的實現。程序框架主要包含三個方面:繪制結構、事件處理結構以及線程結構。在整個框架中,采用當前游戲編程中的通用的狀態控制機制,為每個界面,如菜單、幫助、游戲對話、商店界面設置一個唯一的狀態值,使用該狀態值控制界面的繪制、事件的處理以及線程處理。        在程序的實現上為了通用,以MIDP1.0為基礎來進行制作,這個要比使用MIDP2.0的Game API實現起來要復雜一些。        在類結構的劃分上,為了節約減小jar文件大小,把這個程序代碼劃分為兩個類,一個MIDlet類,一個界面類,所有邏輯代碼以及線程實現均放置在界面類中。        下面是MIDlet類的代碼,主要實現顯示界面、處理手機來電、釋放資源以及退出功能,線程啟動放在界面類中實現。源代碼如下: package myrpg;   import Javax.microedition.midlet.*; import Javax.microedition.lcdui.*;   /**  * RPG結構的MIDlet類  * 包含如下功能:  *    1、顯示界面  *    2、手機來電處理  *    3、釋放資源  *    4、退出方法  */ public class MyRPGMIDlet extends MIDlet {     /**MyRPGMIDlet對象,用於實現退出功能*/     static MyRPGMIDlet instance;     /**界面類對象*/     MyRPGCanvas mainScreen = new MyRPGCanvas();     public MyRPGMIDlet() {         //初始化         instance = this;         //顯示界面         Display.getDisplay(this).setCurrent(mainScreen);     }       public void startApp() {         //開始或繼續游戲         if (mainScreen != null) {             mainScreen.startGame();         }     }       public void pauseApp() {         //暫停游戲         if (mainScreen != null) {             mainScreen.pauseGame();         }     }       public void destroyApp(boolean unconditional) {         //釋放資源         if (mainScreen != null) {             mainScreen.destroyGame();             mainScreen = null;         }     }       /**      * 退出方法      */     public static void quitApp() {         instance.destroyApp(true);         instance.notifyDestroyed();         instance = null;     } }        游戲邏輯和界面繪制以及控制都放在一個類MyRPGCanvas中,這樣實現沒有使用面向對象容易修改和擴展,但是通過結構化代碼,還是可以保證較高的可讀性以及維護性。在MyRPGCanvas中,通過狀態變量status控制界面的繪制以及線程邏輯,為了清晰,把每個處理邏輯都封裝成一個方法,如果方法比較復雜還可以繼續拆分為多個方法。        關於繪制部分,如果每個界面都具有一張不透明的背景圖片的話,可以省略清屏功能,這樣可以提高程序的執行效率。        關於線程部分主要實現了暫停控制,通過isPaused變量來控制邏輯是否執行,從而實現暫停功能,並實現精確的延時。        關於資源加載和銷毀,如果機器的內存不是很緊張的話,可以一次加載,如果內存比較緊張的話,需要編寫專門的代碼控制資源的加載和銷毀。        具體的實現代碼如下: package myrpg; import Javax.microedition.lcdui.*; /**  * 游戲界面,包含所有游戲界面、邏輯以及事件處理  */ public class MyRPGCanvas extends Canvas implements Runnable {     /**游戲是否處於運行狀態,true代表處於運行狀態*/     private boolean isRunning = true;     /**游戲是否處於暫停狀態,true代表處於暫停狀態*/     private boolean isPaused = false;       /**屏幕寬度*/     private int width;     /**屏幕高度*/     private int height;       /**時間間隔*/     private final int INTERVAL_TIME = 100;       /**游戲狀態,使用該變量標示游戲的界面和邏輯*/     private int status;       //各個界面狀態常量     /**Logo界面狀態*/     private final int LOGO_STATUS = 0;     /**菜單界面狀態*/     private final int MENU_STATUS = 1;     /**幫助界面狀態*/     private final int HELP_STATUS = 2;     /**關於界面狀態*/     private final int ABOUT_STATUS = 3;     //游戲中各個狀態常量     /**地圖1狀態*/     private final int GAME_MAP1_STATUS = 4;     /**武器店1狀態*/     private final int GAME_WEAPONSHOP1_STATUS = 5;     /**對話1狀態*/     private final int GAME_DIALOG1_STATUS = 6;       public MyRPGCanvas() {         //初始化         init();         //啟動線程         Thread thread = new Thread(this);         thread.start();     }       /**      * 初始化游戲      * 導入資源和初始化游戲狀態      */     private final void init() {         //獲得屏幕尺寸         width = this.getWidth();         height = this.getHeight();         //初始化游戲狀態,默認顯示LOGO界面         status = LOGO_STATUS;         //導入圖片和其他資源       }       protected void paint(Graphics g) {         //清屏         clearScreen(g);         //繪制         switch (status) {         case LOGO_STATUS:             paintLogo(g);             break;         case MENU_STATUS:             paintMenu(g);             break;         case HELP_STATUS:             paintHelp(g);             break;         case ABOUT_STATUS:             paintAbout(g);             break;         case GAME_MAP1_STATUS:             paintGame_Map1(g);             break;         case GAME_WEAPONSHOP1_STATUS:             paintGame_WeaponShop1(g);             break;         case GAME_DIALOG1_STATUS:             paintDialog1(g);             break;         }     }       /**      * 繪制LOGO界面      * @param g Graphics 畫筆      */     private final void paintLogo(Graphics g) {       }       /**      * 繪制菜單界面      * @param g Graphics 畫筆      */     private final void paintMenu(Graphics g) {       }       /**      * 繪制幫助界面      * @param g Graphics 畫筆      */     private final void paintHelp(Graphics g) {       }       /**      * 繪制關於界面      * @param g Graphics 畫筆      */     private final void paintAbout(Graphics g) {       }       /**      * 繪制游戲地圖1界面      * @param g Graphics 畫筆      */     private final void paintGame_Map1(Graphics g) {       }       /**      * 繪制游戲武器店1界面      * @param g Graphics 畫筆      */     private final void paintGame_WeaponShop1(Graphics g) {       }       /**      * 繪制游戲對話1界面      * @param g Graphics 畫筆      */     private final void paintDialog1(Graphics g) {       }       /**      * 清屏      * @param g Graphics 畫筆      */     private final void clearScreen(Graphics g) {         g.setColor(0xffffff);         g.fillRect(0, 0, width, height);     }       /**      * 開始和繼續游戲      */     public void startGame() {         isPaused = false;     }       /**      * 暫停游戲      */     public void pauseGame() {         isPaused = true;     }       /**      * 釋放資源      * 包括圖片、聲音等資源      */     public void destroyGame() {       }     /**      * logo界面線程邏輯      */     private final void doLogo() {       }     /**      * 幫助界面線程邏輯      */     private final void doHelp() {       }     /**      * 關於界面線程邏輯      */     private final void doAbout() {       }     /**      * 菜單界面線程邏輯      */     private final void doMenu() {       }     /**      * 游戲地圖1界面線程邏輯      */     private final void doGame_Map1() {       }     /**      * 游戲武器店1界面線程邏輯      */     private final void doGame_WeaponShop1() {       }     /**      * 游戲對話1界面線程邏輯      */     private final void doDialog1() {       }       public void run() {         try {             while (isRunning) {                 //精確延時                 long start = System.currentTimeMillis();                   //邏輯處理                 if (!isPaused) {                     switch (status) {                     case LOGO_STATUS:                         doLogo();                         break;                     case MENU_STATUS:                         doMenu();                         break;                     case HELP_STATUS:                         doHelp();                         break;                     case ABOUT_STATUS:                         doAbout();                         break;                     case GAME_MAP1_STATUS:                         doGame_Map1();                         break;                     case GAME_WEAPONSHOP1_STATUS:                         doGame_WeaponShop1();                         break;                     case GAME_DIALOG1_STATUS:                         doDialog1();                         break;                     }                   }                 //重繪                 repaint();                 serviceRepaints();                 long end = System.currentTimeMillis();                 //延時                 if ((end - start) < INTERVAL_TIME) {                    Thread.sleep(INTERVAL_TIME - (end - start));                 }             }         } catch (Exception e) {}     } }        這些只是一個簡單的框架,包含了有些開發中的常見功能的實現,但是尚不包含按鍵處理方面的代碼,如果大家有什麼建議和意見也可以積極提出。   在游戲中,按鍵處理機制也需要小心的實現,這裡就介紹一種實用的按鍵處理機制。        在實際的游戲中,一般為了按鍵靈敏,我們一般不會直接在keyPressed或keyReleased方法內部書寫邏輯的代碼,而只是在這些方法內部記錄或清除按鍵的記錄,而把實際的處理放在線程中進行。這個是本機制中采用的方式。        而且不同手機的按鍵鍵值存在不同,為了方便移植,我們把按鍵轉換成自己定義的數值,然後在程序中使用自定義的值進行處理。        該機制中最核心的變量為;                   private int keyStates;        用該變量中的一個二進制位來代表一種按鍵是否按下,如果按下為1,否則為0。每個按鍵自己進行了定義,定義的代碼如下:                   /**向上*/     private final int KEY_UP = 1;     /**向下*/     private final int KEY_DOWN = 1 << 1;     /**向右*/     private final int KEY_RIGHT = 1 << 2;     /**向左*/     private final int KEY_LEFT = 1 << 3;     /**5鍵*/     private final int KEY_FIRE = 1 << 4;     /**左軟鍵*/     private final int KEY_LEFT_SOFT = 1 << 5;     /**右軟鍵*/     private final int UP = 1 << 6;     /**特殊用途按鍵,例如0鍵*/     private final int KEY_ZERO = 1 << 7;        轉換按鍵鍵值的方法根據手機型號不同,也存在很多的不同,下面是WTK模擬器的實現代碼:                   /**      * 將物理鍵值轉換為自定義鍵值      * 說明:該方法和機型相關,下面是WTK的實現      * @param keyCode 物理鍵值      * @return 自定義鍵值      */     private int convertKey(int keyCode) {         switch (keyCode) {         case -6:             return KEY_LEFT_SOFT;         case -7:             return KEY_RIGHT_SOFT;         case Canvas.KEY_NUM2:         case -1:             return KEY_UP;         case Canvas.KEY_NUM4:         case -3:             return KEY_LEFT;         case Canvas.KEY_NUM6:         case -4:             return KEY_RIGHT;         case Canvas.KEY_NUM8:         case -2:             return KEY_DOWN;         case Canvas.KEY_NUM0:             return KEY_ZERO;         }                       return 0;                   }        按鍵按下時,首先把物理按鍵的鍵值轉換為自定義的鍵值,然後把按鍵信息保存到按鍵狀態變量keyStates中,保存時采用的是位運算符位或實現的。實現代碼如下:            public void keyPressed(int keyCode) {                //轉換按鍵                int key = convertKey(keyCode);                //保存按鍵                keyStates |= key;            }    按鍵釋放時,和按鍵按下類似,首先轉換鍵值,然後清除按鍵信息。清除時把按鍵狀態取反,然後與keyStates位與即可。實現代碼如下:               public void keyReleased(int keyCode) {                //轉換按鍵                int key = convertKey(keyCode);                //清除按鍵                keyStates &= ~key;            }        在界面切換時,需要把按鍵狀態清空,這樣只需要把keyStates清零即可。實現代碼如下:                   /**                   * 清除按鍵                   */                   private void clearKey(){                       keyStates = 0;                   }        實際的按鍵處理的代碼可以在線程中實現。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved