首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 遊戲教學 (四):鍵盤事件處理與按鍵緩衝機制

     編輯:J2ME

三大鍵盤回調方法

方法觸發時機支援度
keyPressed(int keyCode)按鍵按下所有手機
keyReleased(int keyCode)按鍵釋放所有手機
keyRepeated(int keyCode)長按持續觸發大多數不支援,實際由 keyPressed 重複呼叫

實務上僅需實作 keyPressed 與 keyReleased 即可滿足所有需求。

鍵碼跨平台問題

keyCode 為廠商定義原始值,不同手機、模擬器與真機均可能不同。例如按數字鍵 1,不一定對應 keyCode=1。

解決方案:建立邏輯鍵常數映射表,啟動時或設定畫面讓使用者按鍵自動記錄對應 keyCode。

第一版:單一變數記錄 (缺陷版)

int keyValue; // 只能記住最後一個按鍵

public void keyPressed(int keyCode) {
    System.out.println("KeyCode: " + keyCode); // 除錯用
    keyValue = keyCode;
}

// 邏輯判斷
if (keyValue == NUM6) { gameState = 3; keyValue = -1; }

致命缺陷:若玩家極快連按 6 又按 4,keyValue 被 4 覆寫,狀態 2 的判斷完全漏掉 6 被按過。

第二版:位元組旗標 (標準作法)

利用 int 32 位元,每個位元代表一個邏輯鍵狀態:

// 邏輯鍵位元定義
static final int GAME_UP    = 1 << 0; // 0000 0001
static final int GAME_DOWN  = 1 << 1; // 0000 0010
static final int GAME_LEFT  = 1 << 2; // 0000 0100
static final int GAME_RIGHT = 1 << 3; // 0000 1000
static final int GAME_FIRE  = 1 << 4; // 0001 0000
// ... 最多 32 鍵

int keyState = 0; // 當前按鍵狀態位元圖

public void keyPressed(int keyCode) {
    switch (keyCode) {
        case NUM_UP:    keyState |= GAME_UP;    break;
        case NUM_DOWN:  keyState |= GAME_DOWN;  break;
        case NUM_LEFT:  keyState |= GAME_LEFT;  break;
        case NUM_RIGHT: keyState |= GAME_RIGHT; break;
        case NUM_FIRE:  keyState |= GAME_FIRE;  break;
    }
}

public void keyReleased(int keyCode) {
    switch (keyCode) {
        case NUM_UP:    keyState &= ~GAME_UP;    break;
        case NUM_DOWN:  keyState &= ~GAME_DOWN;  break;
        case NUM_LEFT:  keyState &= ~GAME_LEFT;  break;
        case NUM_RIGHT: keyState &= ~GAME_RIGHT; break;
        case NUM_FIRE:  keyState &= ~GAME_FIRE;  break;
    }
}

判斷邏輯:位元運算

// 檢查某鍵是否被按住 (含長按)
boolean isHeld(int gameKey) {
    return (keyState & gameKey) != 0;
}

// 檢查某鍵是否在「這一幀」被按下 (需配合幀緩衝)
boolean isPressedThisFrame(int gameKey) {
    return (framePressedKeys & gameKey) != 0;
}

第三版:幀緩衡機制 (專業級)

問題:keyState 隨時可能被中斷修改,若在遊戲邏輯中間直接讀取,會導致同一幀內判斷結果不一致。

解決:每幀開始時快照一份不變的副本供邏輯使用。

int frameKeyState;      // 本幀按鍵狀態快照
int framePressedKeys;   // 本幀新按下的鍵
int frameReleasedKeys;  // 本幀釋放的鍵

// 每幀開頭呼叫 (在 run() 迴路最前面)
private void acquireInput() {
    frameKeyState = keyState;
    framePressedKeys = pressedKeysBuffer;
    frameReleasedKeys = releasedKeysBuffer;
    pressedKeysBuffer = 0;
    releasedKeysBuffer = 0;
}

// 修正後的回調
public void keyPressed(int keyCode) {
    int bit = getGameKeyBit(keyCode); // 映射到 GAME_* 常數
    keyState |= bit;
    pressedKeysBuffer |= bit; // 記錄這一幀有被按下
}

public void keyReleased(int keyCode) {
    int bit = getGameKeyBit(keyCode);
    keyState &= ~bit;
    releasedKeysBuffer |= bit; // 記錄這一幀有被釋放
}

// 遊戲邏輯中只用快照判斷
if ((frameKeyState & GAME_RIGHT) != 0) { /* 角色向右移動 */ }
if ((framePressedKeys & GAME_FIRE) != 0) { /* 發射子彈 */ }

實作完整範例:狀態 2/3 切換

// Game.java 片段
static final int NUM4 = 52;  // 實測填入
static final int NUM6 = 54;
static final int GAME_NUM4 = 1 << 4;
static final int GAME_NUM6 = 1 << 6;

int keyState = 0;
int frameKeyState, framePressedKeys;

public void keyPressed(int keyCode) {
    if (keyCode == NUM4) keyState |= GAME_NUM4;
    else if (keyCode == NUM6) keyState |= GAME_NUM6;
}

public void keyReleased(int keyCode) {
    if (keyCode == NUM4) keyState &= ~GAME_NUM4;
    else if (keyCode == NUM6) keyState &= ~GAME_NUM6;
}

private void acquireInput() {
    frameKeyState = keyState;
    framePressedKeys = pressedKeysBuffer; // 需額外維護 pressedKeysBuffer
    pressedKeysBuffer = 0;
}

// 狀態機判斷
switch (gameState) {
    case 2:
        if ((framePressedKeys & GAME_NUM6) != 0) {
            gameState = 3;
            framePressedKeys &= ~GAME_NUM6; // 清除已處理
        }
        break;
    case 3:
        if ((framePressedKeys & GAME_NUM4) != 0) {
            gameState = 2;
            framePressedKeys &= ~GAME_NUM4;
        }
        break;
}

總結

  1. 採用位元組旗標而非單一變數,支援多鍵同時判斷。
  2. 引入幀緩衝快照,保證同一幀邏輯判斷一致性。
  3. 區分長按狀態 (frameKeyState) 與瞬時按下 (framePressedKeys)。
  4. 鍵碼映射表需支援運行時配置,適配不同機型。

這套機制雖簡單,卻是商業級 J2ME 遊戲輸入系統的核心骨架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved