J2ME 低階 UI(Canvas/GameCanvas)中,鍵盤事件處理直接決定遊戲手感。本文以手機鍵盤為核心,系統比較三種處理模式的機制、適用場景與優劣。
Canvas.KEY_NUM0 ~ KEY_NUM9、KEY_STAR、KEY_POUND 跨裝置一致。Canvas 子類別覆寫 keyPressed(int keyCode),系統事件執行緒於按鍵按下時回呼,傳入鍵值。
// 寫法 A:硬編碼數值(不可讀、不可維護)
if (keyCode == 52) { ... }
// 寫法 B:使用 Canvas 常數(推薦)
if (keyCode == Canvas.KEY_NUM4) { ... }
將物理鍵映射為邏輯遊戲動作,由裝置製造商實作映射表:
int action = getGameAction(keyCode);
switch (action) {
case Canvas.LEFT: // 數字鍵 4 + 向左導航鍵
case Canvas.RIGHT: // 數字鍵 6 + 向右導航鍵
case Canvas.UP: // 數字鍵 2 + 向上導航鍵
case Canvas.DOWN: // 數字鍵 8 + 向下導航鍵
case Canvas.FIRE: // 數字鍵 5 + 確認鍵
case Canvas.GAME_A: case Canvas.GAME_B: case Canvas.GAME_C: case Canvas.GAME_D:
// 對應 1/3/7/9 或 7/9/*/#,視裝置而定
}
優點:跨裝置相容性佳、邏輯清晰。缺點:仍綁定於 keyPressed 回呼,三大遊戲邏輯(延遲、輸入響應、重繪)混雜於系統事件執行緒,難以精確控制幀率。
public class MyGameCanvas extends GameCanvas {
public MyGameCanvas() {
super(true); // true = 啟用按鍵狀態追蹤
}
}
注意:啟用後,遊戲相關按鍵不再觸發 keyPressed,其他鍵(如軟鍵)仍正常回呼。
// 於遊戲主迴圈(獨立執行緒)呼叫
int states = getKeyStates(); // 取得並清除當前狀態位元遮罩
// 位元運算判斷
if ((states & GameCanvas.LEFT_PRESSED) != 0) { /* 向左 */ }
if ((states & GameCanvas.RIGHT_PRESSED) != 0) { /* 向右 */ }
if ((states & GameCanvas.UP_PRESSED) != 0) { /* 向上 */ }
if ((states & GameCanvas.DOWN_PRESSED) != 0) { /* 向下 */ }
if ((states & GameCanvas.FIRE_PRESSED) != 0) { /* 確認/開火 */ }
getKeyStates() 即可檢測組合鍵(如斜向移動)。| 按鍵類型 | 處理模式 | 理由 |
|---|---|---|
| 方向鍵、確認鍵、數字鍵 2/4/5/6/8 | keyStates 輪詢 | 遊戲核心操作,需精準幀同步、多鍵組合 |
| 左右軟鍵、功能鍵、*、#、通話鍵 | keyPressed 事件 | 非遊戲邏輯(選單、暫停、音量),事件驅動更自然 |
| 需偵測「按下/釋放」邊緣觸發 | keyPressed + keyReleased | keyStates 僅提供「按下狀態」,無釋放事件 |
InputHandler 介面,提供 KeyPressedImpl 與 KeyStatesImpl 兩種實作,運行期檢測 GameCanvas 類別是否存在決定注入哪種。getKeyStates() 呼叫頻率 = 遊戲幀率(建議 20-30fps),過高無意義、過低導致輸入延遲。paint() 前呼叫 getKeyStates(),確保輸入與渲染同幀處理。從 keyPressed 到 gameAction 再到 keyStates,J2ME 輸入處理經歷了「硬編碼鍵值 → 邏輯動作映射 → 狀態輪詢」三代演進。現代手機遊戲開發應以 keyStates 為核心,輔以事件處理非遊戲鍵,構建穩定、跨裝置相容的輸入系統。