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

J2ME 按鍵長按重複觸發實現:獨立線程輪詢模式完整代碼

     編輯:J2ME

背景

部分手機不支持原生按鍵重複事件 (keyRepeated 不觸發)。需自行實現「按下 → 延遲 → 以固定間隔重複觸發」邏輯。

核心設計:按鍵狀態管理器 + 處理線程

public class KeyRepeater implements Runnable {
    private final Canvas canvas;
    private final byte[] pressedKeys = new byte[2]; // 支持最多 2 鍵同時長按
    private byte idx = 0;
    private volatile boolean running = true;

    public KeyRepeater(Canvas canvas) { this.canvas = canvas; }

    // keyPressed 註冊按下的鍵
    public synchronized void keyPressed(int keyCode) {
        pressedKeys[idx] = (byte) keyCode;
        idx = (byte) ((idx + 1) % pressedKeys.length);
    }

    // keyReleased 移除釋放的鍵
    public synchronized void keyReleased(int keyCode) {
        for (int i = 0; i < pressedKeys.length; i++) {
            if (pressedKeys[i] == keyCode) {
                pressedKeys[i] = 0;
                break;
            }
        }
    }

    // 處理線程主循環
    public void run() {
        while (running) {
            byte[] keys = getActiveKeys(); // 獲取當前按下的鍵碼快照
            for (int keyCode : keys) {
                if (keyCode != 0) {
                    int action = canvas.getGameAction(keyCode);
                    // 分發邏輯動作 (示例:移動像素點)
                    switch (action) {
                        case Canvas.UP:    canvas.py--; break;
                        case Canvas.DOWN:  canvas.py++; break;
                        case Canvas.LEFT:  canvas.px--; break;
                        case Canvas.RIGHT: canvas.px++; break;
                    }
                }
            }
            if (hasActiveKey(keys)) canvas.repaint();
            sleep(100); // 重複間隔 100ms,可配置
        }
    }

    private synchronized byte[] getActiveKeys() {
        return pressedKeys.clone();
    }
    private boolean hasActiveKey(byte[] keys) {
        for (byte k : keys) if (k != 0) return true;
        return false;
    }
    private void sleep(long ms) {
        try { Thread.sleep(ms); } catch (InterruptedException ignored) {}
    }
    public void stop() { running = false; }
}

Canvas 集成示例

public class GameCanvas extends Canvas {
    public int px = 50, py = 50;
    private KeyRepeater repeater;

    public GameCanvas() {
        repeater = new KeyRepeater(this);
        new Thread(repeater).start();
    }

    protected void keyPressed(int keyCode) {
        repeater.keyPressed(keyCode);
    }
    protected void keyReleased(int keyCode) {
        repeater.keyReleased(keyCode);
    }

    protected void paint(Graphics g) {
        g.setColor(0xFFFFFF); g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(0xFF0000); g.fillRect(px, py, 8, 8); // 繪製移動方塊
    }
}

關鍵點解析

  1. 狀態分離:事件回調 (keyPressed/Released) 僅維護「哪些鍵被按下」集合,不包含邏輯。
  2. 獨立線程輪詢:run() 循環定期檢查集合,將物理鍵碼轉邏輯動作 (getGameAction) 並執行遊戲邏輯。
  3. 同步保護:集合讀寫用 synchronized,避免併發修改異常。
  4. 間隔可配置:sleep(100) 控制重複頻率,可根據遊戲類型調整 (動作遊戲 50-100ms,策略遊戲 200-500ms)。
  5. 多鍵並發:數組支持多鍵同時長按 (如斜向移動)。

優化建議

  • 首次觸發延遲 (初次按下 → 首次重複) 通常比重複間隔長 (如 500ms vs 100ms),可引入 firstDelay 狀態機。
  • 釋放鍵時立即停止該鍵的重複邏輯 (已通過移除數組元素實現)。
  • MIDlet destroyApp 中調用 repeater.stop() 優雅關閉線程。

總結

通過「事件註冊狀態 + 獨立線程輪詢分發」模式,可在不支持原生重複事件的設備上完美模擬按鍵長按重複,代碼結構清晰、擴展性強,適合各類即時性遊戲。

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