keyPressed/Released 僅在按鍵發生時觸發,但遊戲邏輯(重力、AI、動畫)需每幀推進。專業做法:事件層只記錄狀態,邏輯層輪詢狀態。
另一痛點:不同機型物理鍵碼不同(Nokia 左軟鍵 -6,Moto C650 -21)。解決方案:定義虛擬鍵碼,映射層吸收差異。
private int keyStates; // 32 位足夠覆蓋所有鍵
// 虛擬鍵常量(2 的 n 次方)
private final int KEY_UP = 1 << 0;
private final int KEY_DOWN = 1 << 1;
private final int KEY_RIGHT = 1 << 2;
private final int KEY_LEFT = 1 << 3;
private final int KEY_FIRE = 1 << 4;
private final int KEY_LEFT_SOFT = 1 << 5;
private final int KEY_RIGHT_SOFT = 1 << 6;
private final int KEY_ZERO = 1 << 7;
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;
}
public void keyPressed(int keyCode) {
int key = convertKey(keyCode);
keyStates |= key; // 置 1
}
public void keyReleased(int keyCode) {
int key = convertKey(keyCode);
keyStates &= ~key; // 清 0
}
// 切換場景時清空殘留狀態
private void clearKey() { keyStates = 0; }
在遊戲主迴路調用 acquireKey() 快照當前幀狀態,再提供三大查詢:
keyHold(k):長按檢測(至少上一幀已按下)keyDown(k):本幀新按下keyUp(k):本幀釋放實現只需 (frameKey & k) != 0 等位測試,極致高效。此為最小可用集;商業項目可擴展連發計數、組合鍵、按鍵隊列等高級特性。