押下判定の原理
これ迄押下判定はif文で表現していました。
public void keyMovement() {
  final int nKS = getKeypadState();
  if ((nKS & 1 << Display.KEY_LEFT) != 0) {
    mex--;
  } else if ((nKS & 1 << Display.KEY_RIGHT) != 0) {
    mex++;
  }
}
例えばこの様なものです。これは十字キーの左右で左右移動を反映させています。
では、次の画面を見て下さい。
1〜12選択画面
これは十字キーの左右で12コマを選択する画面です。当然ながら右を押せば右へ、左なら左へそのフォーカスが1コマ移動します。
以下にプログラムを挙げます。
public void run() {
  for (;;) {
    repaint(0, 0, 240, 240);
    try {
      Thread.sleep(30);
    } catch (InterruptedException e) {
    }
    time++;
    keyMovement();
  }
}
public void keyMovement() {
  final int nKS = getKeypadState();
  if ((nKS & 1 << Display.KEY_LEFT) != 0) {
    mex--;
    //最後尾へジャンプ
    if (mex < 0) {
      mex = 11;
    }
  } else if ((nKS & 1 << Display.KEY_RIGHT) != 0) {
    mex++;
    //先頭へジャンプ
    if (11 < mex) {
      mex = 0;
    }
  }
}
このプログラムをコピー&ペーストし、1度動かしてみて下さい。
すると理論上は上手く行く筈のフォーカス移動が、なかなかユーザの目的地点で止まってくれない事が解ると思います。
これは、スレッドが繰り返される度にキー入力判定を通っている事が原因です。
一度の判定で1コマ移動する様にしていても、その判定の間隔が短過ぎる為にユーザの押下は細かく処理されます。
一度の押下が何度も判定される様子
ディレイ
この現象を回避する為に、押下判定部分を操作しましょう。
現時点では毎回判定していた為、この様な不良が生じます。そこで、その判定間隔を一定間隔ずつ保つ様にするのです。
具体的には以下のプログラムになります。
public void run() {
  for (;;) {
    repaint(0, 0, 240, 240);
    try {
      Thread.sleep(30);
    } catch (InterruptedException e) {
    }
    time++;
    if (time - delay > 5) {
      keyMovement();
    }
  }
}
public void keyMovement() {
  final int nKS = getKeypadState();
  if ((nKS & 1 << Display.KEY_LEFT) != 0) {
    mex--;
    delay = time;
    //最後尾へジャンプ
    if (mex < 0) {
      mex = 11;
    }
  } else if ((nKS & 1 << Display.KEY_RIGHT) != 0) {
    mex++;
    delay = time;
    //先頭へジャンプ
    if (11 < mex) {
      mex = 0;
    }
  }
}
フィールドdelayを設け、押下判定受理時にそこへ現在timeが持つ値を代入します。
run()メソッドからkeyMovement()が呼ばれる条件は"time - delay > 5"、つまり押下した時から最低でも6フレーム経過しないと次の受理自体されなくなります。
実際にこのプログラムを動かしてみれば、今度はきちんと意図するコマへフォーカスが合わせられる様になっている筈です。
今回は押下判定を態と遅らせています。この様に、意図的な間隔操作をディレイ ―Delay― と呼びます。
ディレイを上手く使えば複雑な条件分岐であっても、きちんと意図する場所で止められる様になるでしょう。
inserted by FC2 system