| 方式 | 代碼示例 | 優缺點 |
| 直接比較 keyCode | if (keyCode == 52) ... 或 if (keyCode == Canvas.KEY_NUM4) ... | ✅ 可讀性差(魔術數字) / ✅ 推薦用常量 |
| gameAction 映射 | int action = getGameAction(keyCode);
switch(action) { case Canvas.LEFT: ... } | ✅ 屏蔽設備差異 / ✅ 遊戲邏輯統一 |
3. gameAction 映射表 (設備廠商實現)
| Game Action | 典型物理鍵 |
| Canvas.UP | 數字鍵 2、向上導航鍵 |
| Canvas.DOWN | 數字鍵 8、向下導航鍵 |
| Canvas.LEFT | 數字鍵 4、向左導航鍵 |
| Canvas.RIGHT | 數字鍵 6、向右導航鍵 |
| Canvas.FIRE | 數字鍵 5、確定/中間鍵 |
| Canvas.GAME_A/B/C/D | 1/3/7/9 或 7/9/*/# (設備差異大) |
4. 核心缺陷:三大邏輯強耦合
// 在系統事件線程 (EDT) 中執行
protected void keyPressed(int keyCode) {
// 1. 響應用戶操作
// 2. 更新遊戲狀態 (邏輯)
// 3. 觸發重繪 repaint()
}
// 導致:邏輯執行時間長 → 界面卡頓、按鍵丟失、重繪不及時
二、第二代:keyStates 位掩碼機制 (MIDP 2.0 GameCanvas)
1. 核心原理
- 系統維護一個
int 位掩碼,每位對應一個遊戲動作 (UP/DOWN/LEFT/RIGHT/FIRE/GAME_A-D)
- 按鍵按下 → 對應位置 1;釋放 → 置 0
- 開發者在**遊戲主線程**中主動輪詢:
int states = getKeyStates();
- 關鍵優勢:讀取瞬間**自動清零**,保證不重複處理;脫離
keyPressed 線程,邏輯/渲染完全可控
2. 使用前提
public class MyGameCanvas extends GameCanvas {
public MyGameCanvas() {
super(true); // true = 啟用 keyStates 機制
}
public void run() { // 遊戲主線程
while (running) {
int states = getKeyStates(); // 獲取並清零
if ((states & LEFT_PRESSED) != 0) { /* 向左 */ }
if ((states & RIGHT_PRESSED) != 0) { /* 向右 */ }
// ... 更新邏輯
repaint(); // 主動觸發渲染
Thread.sleep(frameDelay);
}
}
}
3. 位掩碼常量 (GameCanvas 定義)
LEFT_PRESSED = 1 << 0 // 0x01
RIGHT_PRESSED = 1 << 1 // 0x02
UP_PRESSED = 1 << 2 // 0x04
DOWN_PRESSED = 1 << 3 // 0x08
FIRE_PRESSED = 1 << 4 // 0x10
GAME_A_PRESSED = 1 << 5 // 0x20
GAME_B_PRESSED = 1 << 6 // 0x40
GAME_C_PRESSED = 1 << 7 // 0x80
GAME_D_PRESSED = 1 << 8 // 0x100
4. 限制條件
- 僅限
GameCanvas 子類且構造器傳 true
- 僅處理遊戲相關鍵 (上下左右火功能鍵);功能鍵(軟鍵/掛機)仍走
keyPressed
- 啟用後,遊戲鍵**不再觸發**
keyPressed
三、三代機制綜合對比
| 維度 | keyPressed + keyCode | keyPressed + gameAction | keyStates (GameCanvas) |
| MIDP 版本 | 1.0+ | 1.0+ | 2.0+ |
| 線程模型 | 系統事件線程 (EDT) | 系統事件線程 (EDT) | 遊戲主線程 (自主控制) |
| 設備適配 | 需處理 keyCode 差異 | 廠商實現映射,較統一 | 同 gameAction,標準位掩碼 |
| 邏輯/渲染分離 | ❌ 強耦合 | ❌ 強耦合 | ✅ 完全分離 |
| 長按/連發處理 | 需自行計時 | 需自行計時 | ✅ 位狀態持續為 1,自然支持 |
| 按鍵衝突/丟失 | 高風險 | 高風險 | 低風險 (輪詢快照) |
| 功能鍵支持 | ✅ 全鍵盤 | ❌ 僅遊戲鍵 | ❌ 僅遊戲鍵 (功能鍵仍需 keyPressed) |
| 代碼複雜度 | 低 | 中 | 中高 (需管理遊戲循環) |
四、最佳實踐建議
- 純 MIDP 1.0 設備:
gameAction 映射 + 簡單狀態機,避免在 keyPressed 執行耗時邏輯
- MIDP 2.0 遊戲首選:繼承
GameCanvas,啟用 keyStates,構建標準遊戲循環 (輸入→邏輯→渲染→休眠)
- 混合模式:遊戲鍵用
keyStates,功能鍵(暫停/菜單/退出)覆蓋 keyPressed 處理
- 位運算封裝:定義
isPressed(states, GAME_LEFT) 工具方法,提升可讀性
- 幀率固定:
Thread.sleep(1000 / targetFPS - elapsed) 保證穩定幀率
五、結語
從 keyPressed 的被動響應,到 gameAction 的語義映射,再到 keyStates 的主動輪詢位掩碼,**J2ME 事件處理演進本質是「控制權回歸開發者」**。MIDP 2.0 GameCanvas + keyStates 確立了移動遊戲「主循環 + 輸入快照」的工業級標準模式。現代移動遊戲引擎 (LibGDX, Cocos2d-x, Unity) 底層輸入系統同樣遵循此設計哲學。掌握三代機制本質,即掌握了跨平台遊戲輸入架構的核心邏輯。
- 上一篇文章: JBuilder X 初體驗:里程碑式升級帶來 IDEA 風格代碼折疊、括號匹配與 JBoss 整合
- 下一篇文章: Eclipse 3.1 泛型支持全解析:編譯器設置、錯誤警告配置與重構工具實戰
Copyright ©
程式碼之家 All Rights Reserved