MIDP 1.0 中 Canvas 提供 keyPressed/released/repeated 三大按鍵事件,但部分裝置不支援 keyRepeated(可用 hasRepeatEvents() 檢測)。本文提出「旗標法」:在 keyPressed 設 boolean pressed = true,keyReleased 設 false,遊戲主迴圈中輪詢旗標持續觸發移動邏輯,完美解決跨裝置相容性問題。
private boolean leftPressed, rightPressed;
private int px; // 角色 X 座標
public void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
switch (action) {
case LEFT: left(); leftPressed = true; break;
case RIGHT: right(); rightPressed = true; break;
}
repaint();
}
public void keyReleased(int keyCode) {
int action = getGameAction(keyCode);
switch (action) {
case LEFT: leftPressed = false; break;
case RIGHT: rightPressed = false; break;
}
repaint();
}
// 若裝置支援 repeated,可保留作為優化
public void keyRepeated(int keyCode) {
int action = getGameAction(keyCode);
if (action == LEFT) left();
else if (action == RIGHT) right();
repaint();
}
// 遊戲迴圈 (Runnable)
public void run() {
while (true) {
if (leftPressed) left();
if (rightPressed) right();
try { Thread.sleep(50); } catch (InterruptedException ignored) {}
}
}
private void left() { if (px > 0) px--; }
private void right() { if (px < getWidth()) px++; }
public class KeyActionMIDlet extends MIDlet {
protected void startApp() {
Display.getDisplay(this).setCurrent(new MainCanvas());
}
// pauseApp/destroyApp 留空
}
class MainCanvas extends Canvas implements Runnable {
private String btnText = "";
private boolean leftPressed, rightPressed;
private int px, py;
public MainCanvas() {
px = getWidth()/2; py = getHeight()/2;
new Thread(this).start();
}
// keyPressed/Released/Repeated 如上
public void paint(Graphics g) {
g.setColor(0xFFFFFF); g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0x000000);
g.drawString(btnText, 20, 20, Graphics.LEFT|Graphics.TOP);
g.drawString("J2ME", px, py, Graphics.HCENTER|Graphics.TOP);
}
}
| 優點 | 缺點 |
|---|---|
不依賴 keyRepeated,全裝置相容 | 主迴輪詢消耗 CPU(可調大 sleep 降低) |
| 邏輯集中於 run(),易於擴充(加速、摩擦力、邊界) | 需自行處理多鍵同時按下的優先級 |
| 可精確控制幀率與移動速度解耦 | 若邏輯複雜建議改用定時器 TimerTask |
velocityX,keyPressed 疊加加速度,run() 整合位移並施加摩擦係數。UP/DOWN 旗標,向量合成。keyPressed 記錄時間戳,忽略 50ms 內重複事件。pointerPressed/Dragged/Released 同步設定旗標。