亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 3745 | 回復(fù): 8
打印 上一主題 下一主題

[連載]我的J2ME游戲開發(fā)之路 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2006-05-11 18:18 |只看該作者 |倒序瀏覽
第一章. 計劃簡介

我不想再復(fù)制一大段關(guān)于什么是J2ME的東東~~

因為我自己對編程有一點點的概念,并且以前就已經(jīng)學(xué)習(xí)過基本的JAVA語法,因此我不打算在從最基本的語法開始學(xué)習(xí),為了能夠更快地進(jìn)入狀態(tài),我為自己設(shè)定了一個項目目標(biāo):制作一個FC上的吞食天地2之諸葛孔明傳的手機版本。

首先為了能夠最大程度地調(diào)試代碼,我準(zhǔn)備了一部索愛K700手機,為什么選擇它呢?因為它支持CLDC 1.1和 MIDP 2.0,接著呢它的屏不是很小,最后也是最關(guān)鍵的它很便宜。同時我還準(zhǔn)備了用于在PC上開發(fā)時調(diào)試的JDK/索愛SDK。

然后我就開始準(zhǔn)備我的游戲思路了~

這個游戲是一個RPG,它里面的出場人物大概有500個左右,并且有大量的人物對話和特殊事件,并且各種物品品名繁多,這也是RPG的通常特點。為了能夠最有效地控制這些數(shù)據(jù)內(nèi)容,我并不打算將這些數(shù)據(jù)全部放在代碼中,這樣的好處就是以后維護(hù)的時候非常方便,并不需要為了修改某個人物的形象而翻閱大量的代碼。不過這樣也有難處,因為實際上這樣作的話,整個核心代碼就是一個完整的RPG游戲引擎了~~ 不過這本來就是我的學(xué)習(xí)目的,那么為什么還會怕這點難度呢?GOGOGO~~

整個游戲我把它分為了幾個部分: 1. 主角人物,2.場景管理,3.NPC管理,4.事件管理,5.物品管理以及在用戶界面并不一定能表現(xiàn)出來的6.異常管理和7.系統(tǒng)調(diào)試等七個部分。

明天我就開始我的第一部分主角人物了~~

附件一把,里面是我的這個連載的Demo。

DoE2.tar.gz

40.17 KB, 下載次數(shù): 101

Demo

論壇徽章:
0
2 [報告]
發(fā)表于 2006-05-11 18:26 |只看該作者

第二章. 為游戲創(chuàng)建主角

昨天介紹了一下我的J2ME游戲計劃,那么,今天呢,就接著來看看游戲中主角的設(shè)計吧~

在我的游戲中,我打算讓主角能夠根據(jù)按鍵方向不同而作出不同的反應(yīng),比如按左鍵就轉(zhuǎn)向到左邊,按右鍵就轉(zhuǎn)向到右邊,并且我希望我的主角能夠在我連續(xù)按左鍵的時候表現(xiàn)出一個在走動的動作,而不會就象塊木頭一樣一動不動。

因此,我首先為我的主角準(zhǔn)備了一個連續(xù)動作的PNG文件,這個圖片中包括了8個靜態(tài)單元,分別是向左/右/上/下各2個單元。接下來,我的目標(biāo)就是實現(xiàn)這個動作的變化了。在 MIDP 2.0 (JSR 11 中為了對付這種情況,專門提供了一個class來進(jìn)行處理,它就是鼎鼎有名的Sprite。具體Sprite中的Method請參考詳細(xì)的 JSR 118文檔。在這里我就不再累述,趕緊地把我的代碼貼出來先:


  1. import javax.microedition.lcdui.*;
  2. import javax.microedition.lcdui.game.*;

  3. public class GameObject {
  4.     public int living_times = 0;                                            // 總計運行禎數(shù)限制
  5.     public boolean is_alive = false;
  6.     public Sprite sprite;
  7.     public int frame_speed = 0;                                            // 0 = 每禎更新一個圖片,否則為每x禎更新一個圖片
  8.     public int frame_count = 0;                                            // 每禎運行次數(shù)統(tǒng)計
  9.     private int living_count = 0;                                            // 總計運行禎數(shù)統(tǒng)計
  10.     private int screen_width, screen_height;                            // 屏幕寬度和高度
  11.     public static final int frames_per_action = 2;                        // 每個動作的幀數(shù)
  12.     private int current_direct = -1;                                            // 當(dāng)前方向

  13.     public GameObject(Image img, int frame_width, int frame_height, int screen_width, int screen_height) {
  14.         sprite = new Sprite(img, frame_width, frame_height);
  15.         this.screen_width = screen_width;
  16.         this.screen_height = screen_height;
  17.         reset();
  18.     }

  19.     public void paint(Graphics g) {
  20.         if (!is_alive) return;
  21.         sprite.paint(g);
  22.     }

  23.     public void reset() {
  24.         living_count = 0;
  25.         frame_count = 0;
  26.         is_alive = true;
  27.         sprite.setFrame(0);
  28.     }

  29.     public void update() {
  30.         if (!is_alive) return;
  31.         if (++frame_count > frame_speed) {
  32.             frame_count = 0;
  33.             sprite.nextFrame();
  34.             if (living_times != 0 && ++living_count > living_times) is_alive = false;
  35.         }
  36.     }

  37.     public void move(int relative_x, int relative_y) {
  38.         sprite.move(relative_x, relative_y);
  39.     }

  40.     public void moveto(int absolute_x, int absolute_y) {
  41.         sprite.setPosition(absolute_x, absolute_y);
  42.     }

  43.     // 根據(jù)英雄ID和英雄當(dāng)前方向更新英雄動作
  44.     public void updateByDirect(int brave_id, int direct, int move_x, int move_y) {
  45.         if (direct != current_direct) {
  46.             reset();
  47.             moveto(move_x, move_y);
  48.             int[] frame_sequence = new int[frames_per_action];
  49.             for (int i = 0; i < frames_per_action; i++) frame_sequence[i] = brave_id * frames_per_action * 4 + direct * frames_per_action + i;    // 設(shè)置當(dāng)前動作的圖片序列
  50.             sprite.setFrameSequence(frame_sequence);
  51.             frame_sequence = null;
  52.             current_direct = direct;
  53.             update();
  54.         }
  55.         else {
  56.             moveto(move_x, move_y);
  57.             update();
  58.         }
  59.     }
  60. }
復(fù)制代碼


考慮到以后我還需要設(shè)計場景,并且游戲場景肯定是非常巨大的,因此我并不打算讓我的主角實際移動,因為這樣的話,我需要花費更多的內(nèi)存來同時處理主角的移動和場景的移動。我的想法是在每次按鍵的時候主角僅針對按鍵的不同而作出不同的動作(也就是切換主角Sprite對應(yīng)的frame),而移動的實際上是場景部分,這樣我的主角處理就簡單多了,不容易造成主角/場景同時移動時可能產(chǎn)生的矛盾了。一個比較通俗的比喻:就象車和車外的人,如果車和車外的人一起移動,那么勢必車內(nèi)的人有可能會看不到車外的人某個其他動作,而如果僅僅是車動,那么在車內(nèi)的人看來,車外的人每個動作都一覽無遺。

接下來解釋一下上邊的代碼:

1. sprite = new Sprite(img, frame_width, frame_height);
這里我定義了一個Sprite,它每禎的寬度為 frame_width,高度為 frame_height,并且所有禎都包括在 img 這個 Image 對象中。 img 應(yīng)該為使用 Image:createImage 方法創(chuàng)建的一個 Image 對象。根據(jù)Sprite的機制,如果我的這個 img 指定的圖片文件寬度為 frame_width * 2,高度為 frame_height * 3,那么 sprite 中的禎總數(shù)就應(yīng)該是6。

2. int[] frame_sequence = new int[frames_per_action];
for (int i = 0; i < frames_per_action; i++) frame_sequence[ i ] = brave_id * frames_per_action * 4 + direct * frames_per_action + i;
sprite.setFrameSequence(frame_sequence);
這里用到了Sprite的一個方法 setFrameSequence(int[] sequence),它用來定義 Sprite中可供使用的禎序列,從它的類型 int[] 可以看出它實際上是一個數(shù)組,這個數(shù)組的元素就是可供使用的每禎在Sprite實例中的禎Id。比如我用 1 的代碼創(chuàng)建了一個包括8禎的 Sprite,而根據(jù)實際情況我只需要暫時使用第 2/4/6/8 禎,那么我就需要使用 setFrameSequence 來指定我暫時需要使用的禎序列,sequence 就應(yīng)該是 { 2, 4, 6, 8 }。
然后再來看看我這里的代碼:
frame_sequence[ i ] = brave_id * frames_per_action * 4 + direct * frames_per_action + i;
為什么是這樣的呢? brave_id 是我的主角形象ID,因為我的主角并不總是一個人物,它可能在修改游戲人物隊列順序以后發(fā)生改變,因此我在這里定義了一個 brave_id 以適應(yīng)以后的應(yīng)用。direct 是當(dāng)前主角的方向。
這樣這段代碼就容易理解了,frame_sequence[ i ]實際上就是每個方向上的動作在Sprite中的禎ID。

最后,附件是我的主角動作圖片文件。

braves.png (2.7 KB, 下載次數(shù): 66)

主角動作圖片

主角動作圖片

論壇徽章:
0
3 [報告]
發(fā)表于 2006-05-12 09:37 |只看該作者
頂著先,下班回去以后繼續(xù)寫。。。

論壇徽章:
0
4 [報告]
發(fā)表于 2006-05-12 13:53 |只看該作者
牛的

論壇徽章:
0
5 [報告]
發(fā)表于 2006-05-12 14:10 |只看該作者
第一頁的時候留個名, 混個臉熟, 前些時候還有人問我J2EE有前途還是J2ME有前途, 我說我現(xiàn)在老了, 不適合再鉆研另外一個技術(shù), 不如去讀個MBA.

論壇徽章:
0
6 [報告]
發(fā)表于 2006-05-27 11:15 |只看該作者

第三章. 游戲地圖的繪制

在前一章里面,我介紹了我的主角設(shè)計思想:只讓主角對對應(yīng)的按鍵做出相應(yīng)的動作,但實際上并不發(fā)生位移。那么肯定就有朋友會問了:一個RPG里面主角都不能發(fā)生位移,那能算是個RPG么?今天咱們就來解決看上去主角沒有位移的問題。
在前面我也提到了一個相對移動的概念,所以我在這里不再重復(fù)了。今天咱們就來仔細(xì)看看游戲地圖(背景)的實現(xiàn),通過移動繪制地圖,我們就可以讓主角相對移動起來。

首先,我們先將該死的移動繪制地圖拋開,考慮一下我們的地圖大小吧。在一個RPG里面,主要的組成部分就是龐大的地圖,巨大的文字量。也就是說我們的地圖可能會以一個大怪物的身份登場,這個大怪物很有可能會將移動設(shè)備那可憐的內(nèi)存一口吃掉,甚至讓你的移動設(shè)備罷工。同時由于移動設(shè)備的屏幕大小是完全固定的,用戶能看到的地圖范圍是固定的,因此我就想是不是只繪制用戶所能看到的范圍大小,而不是完全繪制地圖呢?很明顯的,這個思路能夠大量地節(jié)約內(nèi)存,并且能夠達(dá)到盡量高效地輸出圖象楨的目的。
下邊就是我用來繪制可視范圍的方法:

  1. public void setAllCells(int offset_block_columns, int offset_block_rows) {
  2.         int new_block_column, new_block_row;
  3.         for (int i = 0; i < blocks_rows; i++) {
  4.                 for (int j = 0; j < blocks_columns; j++) {
  5.                         new_block_column = j + offset_block_columns;
  6.                         new_block_row = i + offset_block_rows;
  7.                         if (
  8.                                 new_block_column >= 0 && new_block_column < current_map_data[0].length
  9.                                 && new_block_row >= 0 && new_block_row < current_map_data.length - 1
  10.                         ) tiled_layer.setCell(j, i, parseModel(current_map_data[new_block_row][new_block_column]));
  11.                         else tiled_layer.setCell(j, i, 0);
  12.                 }
  13.         }
  14. }
  15. private int parseModel(String block_content) {
  16.         int p = block_content.indexOf("|");
  17.         if (p != -1) return Integer.parseInt(block_content.substring(0, p).trim());
  18.         else return Integer.parseInt(block_content.trim());
  19. }
復(fù)制代碼

傳遞的兩個參數(shù)分別是當(dāng)前主角相對啟始點的X位移和Y位移,每次按一次向左方向鍵,這個相對X位移就減1,每次按一次向上方向鍵,相對Y位移就加1。然后在繪制地圖的時候,我首先根據(jù)這兩個參數(shù)找到可視范圍的左上角在實際地圖數(shù)據(jù)中的位置(new_block_column 和 new_block_row),然后因為固定移動設(shè)備的屏幕大小是固定的,因此就可以根據(jù)這些繪制出可視范圍內(nèi)的所有地圖元素了。

接著,讓我們來想想如果我們的地圖不僅僅是一張,比如分為了城市/野外/室內(nèi)幾種,那么我們不可能為每一張地圖都寫一個繪制方法吧?我們要考慮到方法復(fù)用,因此我就生成了一個專用的地圖讀取繪制類。這個地圖讀取繪制類的作用就是首先從地圖配置文件里面讀取數(shù)據(jù),然后將這個數(shù)據(jù)存放在緩沖中供繪制方法使用。

最后看看我的完整的地圖繪制類吧:

  1. // 地圖繪制工具
  2. /* *
  3. *  地圖格式
  4. *
  5. *  模型ID|事件描述
  6. *  地圖最后一行為初始地圖絕對坐標(biāo),如果不傳入需要前往的地圖絕對坐標(biāo),則使用該初始絕對坐標(biāo)
  7. * */
  8. /*
  9. *  事件格式
  10. *        事件類型|事件是否自動運行|事件發(fā)生地圖ID|事件需求類型|事件需求|允許輸入|事件完成以后當(dāng)前任務(wù)ID
  11. *        101|0|切換的目標(biāo)地圖ID|在目標(biāo)地圖的絕對塊X坐標(biāo)|在目標(biāo)地圖的絕對塊Y坐標(biāo)|0|0        切換地圖
  12. *        102|1|NPC ID|0|0|0|0        自動對話。事件需求類型為任務(wù),需求當(dāng)前任務(wù)ID為0,不允許輸入。輸出的是ID為 NPC ID 的NPC對話
  13. *  事件類型
  14. *        事件ID<100則不能移動,即不監(jiān)聽上下左右按鍵事件
  15. *        2        對話
  16. *        101        切換地圖
  17. */
  18. import javax.microedition.lcdui.*;
  19. import javax.microedition.lcdui.game.*;
  20. import java.lang.Math;

  21. public class BackgroundLayer {

  22.         private int screen_width, screen_height;        // 屏幕寬、高度
  23.         public static final int cell_width = 16;                // 地圖單元格寬度
  24.         public static final int cell_height = 16;                // 地圖單元格高度
  25.         private TiledLayer tiled_layer;
  26.         private String[][] current_map_data;                // 當(dāng)前地圖的數(shù)據(jù)
  27.         private int current_map_id;                                        // 當(dāng)前地圖ID
  28.         public static int blocks_columns, blocks_rows;        // 屏幕最大塊列數(shù)和行數(shù)
  29.         private int start_block_x, start_block_y;                // 起始絕對坐標(biāo)

  30.         // 構(gòu)造器
  31.         public BackgroundLayer(int screen_width, int screen_height) {
  32.                 this.screen_width = screen_width;
  33.                 this.screen_height = screen_height;
  34.                 blocks_columns = (int)Math.ceil(screen_width / cell_width);        // 單元格列數(shù)
  35.                 blocks_rows = (int)Math.ceil(screen_height / cell_height);        // 單元格行數(shù)
  36.         }

  37.         // 裝載指定地圖
  38.         public String[][] loadMapData(int map_id) {
  39.                 if (current_map_id != map_id) {
  40.                         FileTool file_tool = new FileTool();
  41.                         current_map_data = file_tool.readFromTxtFile("/res/maps/" + map_id + ".txt");
  42.                         file_tool = null;
  43.                         current_map_id = map_id;
  44.                         this.start_block_x = Integer.parseInt(current_map_data[current_map_data.length - 1][0]);
  45.                         this.start_block_y = Integer.parseInt(current_map_data[current_map_data.length - 1][1]);
  46.                         tiled_layer = null;
  47.                         System.gc();
  48.                         try {
  49.                                 tiled_layer = new TiledLayer(blocks_columns, blocks_rows, Image.createImage("/res/images/background/" + current_map_data[current_map_data.length - 1][2] + ".png"), cell_width, cell_height);
  50.                         }
  51.                         catch (Exception e) { }
  52.                 }
  53.                 return current_map_data;
  54.         }

  55.         // 裝載指定地圖
  56.         public String[][] loadMapData(int map_id, int start_block_x, int start_block_y) {
  57.                 if (current_map_id != map_id) {
  58.                         FileTool file_tool = new FileTool();
  59.                         current_map_data = file_tool.readFromTxtFile("/res/maps/" + map_id + ".txt");
  60.                         file_tool = null;
  61.                         current_map_id = map_id;
  62.                         this.start_block_x = start_block_x;
  63.                         this.start_block_y = start_block_y;
  64.                         tiled_layer = null;
  65.                         System.gc();
  66.                         try {
  67.                                 tiled_layer = new TiledLayer(blocks_columns, blocks_rows, Image.createImage("/res/images/background/" + current_map_data[current_map_data.length - 1][2] + ".png"), cell_width, cell_height);
  68.                         }
  69.                         catch (Exception e) { }
  70.                 }
  71.                 return current_map_data;
  72.         }

  73.         public void paint(Graphics g) {
  74.                 tiled_layer.paint(g);
  75.         }

  76.         // 根據(jù)地圖范圍設(shè)置顯示區(qū)域的模型內(nèi)容
  77.         public void setAllCells(int offset_block_columns, int offset_block_rows) {
  78.                 int new_block_column, new_block_row;
  79.                 for (int i = 0; i < blocks_rows; i++) {
  80.                         for (int j = 0; j < blocks_columns; j++) {
  81.                                 new_block_column = j + offset_block_columns;
  82.                                 new_block_row = i + offset_block_rows;
  83.                                 if (
  84.                                         new_block_column >= 0 && new_block_column < current_map_data[0].length
  85.                                         && new_block_row >= 0 && new_block_row < current_map_data.length - 1
  86.                                 ) tiled_layer.setCell(j, i, parseModel(current_map_data[new_block_row][new_block_column]));
  87.                                 else tiled_layer.setCell(j, i, 0);
  88.                         }
  89.                 }
  90.         }

  91.         // 根據(jù)地圖范圍設(shè)置顯示區(qū)域的模型內(nèi)容
  92.         // default_block_id 缺省的模型ID,超出地圖配置文件范圍的內(nèi)容使用該塊繪制
  93.         public void setAllCells(int offset_block_columns, int offset_block_rows, int default_block_id) {
  94.                 int new_block_column, new_block_row;
  95.                 for (int i = 0; i < blocks_rows; i++) {
  96.                         for (int j = 0; j < blocks_columns; j++) {
  97.                                 new_block_column = j + offset_block_columns;
  98.                                 new_block_row = i + offset_block_rows;
  99.                                 if (
  100.                                         new_block_column >= 0 && new_block_column < current_map_data[0].length
  101.                                         && new_block_row >= 0 && new_block_row < current_map_data.length - 1
  102.                                 ) tiled_layer.setCell(j, i, parseModel(current_map_data[new_block_row][new_block_column]));
  103.                                 else tiled_layer.setCell(j, i, default_block_id);
  104.                         }
  105.                 }
  106.         }

  107.         // 解析地圖模型內(nèi)容
  108.         private int parseModel(String block_content) {
  109.                 int p = block_content.indexOf("|");
  110.                 if (p != -1) return Integer.parseInt(block_content.substring(0, p).trim());
  111.                 else return Integer.parseInt(block_content.trim());
  112.         }

  113.         // 解析英雄所在塊數(shù)據(jù)內(nèi)容
  114.         // 第一元素為事件類型,小于MainGameCanvas.STATUS_IN_MOVING的事件類型不能移動
  115.         // 其他參考 EventManager中的說明
  116.         public int[] parseBlock(int offset_x, int offset_y) {
  117.                 int[] block_info = new int[7];
  118.                 int brave_position_x = blocks_columns / 2 + offset_x;
  119.                 int brave_position_y = blocks_rows / 2 + offset_y;
  120.                 if (
  121.                         brave_position_x >= 0 && brave_position_x < current_map_data[0].length
  122.                         && brave_position_y >= 0 && brave_position_y < current_map_data.length - 1
  123.                         )
  124.                 {
  125.                         String tmp = current_map_data[brave_position_y][brave_position_x];
  126.                         int p = tmp.indexOf("|");
  127.                         int i = 0;
  128.                         if (p != -1) {
  129.                                 while ((p = tmp.indexOf("|")) != -1) {
  130.                                         if (i > 0) block_info[i - 1] = Integer.parseInt(tmp.substring(0, p).trim());        // 跳過地圖模型描述字段
  131.                                         tmp = tmp.substring(p + 1);
  132.                                         i++;
  133.                                 }
  134.                                 block_info[i - 1] = Integer.parseInt(tmp.trim());
  135.                         }
  136.                         else block_info[0] = MainGameCanvas.STATUS_IN_MOVING;
  137.                 }
  138.                 else block_info[0] = MainGameCanvas.STATUS_IN_GAMING;
  139.                 return block_info;
  140.         }

  141.         public int getStartOffset(boolean is_x) {
  142.                 if (is_x) return start_block_x - blocks_columns / 2;
  143.                 else return start_block_y - blocks_rows / 2;
  144.         }
  145. }
復(fù)制代碼


其中用到了一個我的自定義類 FileTool,這個文件我在下一次再發(fā)上來吧~~

論壇徽章:
0
7 [報告]
發(fā)表于 2007-07-31 17:30 |只看該作者
怎么沒有了
繼續(xù)阿

論壇徽章:
0
8 [報告]
發(fā)表于 2007-08-01 09:42 |只看該作者
強貼留名.....

論壇徽章:
0
9 [報告]
發(fā)表于 2007-08-17 08:29 |只看該作者
頂一下
還有下文嗎?
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP