2018/02/21

押しっぱなしのkeydownまたはkeypressイベントの初動をスムーズにする

勉強がてらCanvasをつかったブラウザゲームを作っている。そこでkeydownまたはkeypressイベントでCanvas内に描画したオブジェクトを動かそうとしたときに問題が生じた。

次のgifアニメを見てほしい。

これは矢印キーを押しっぱなしにしたときのオブジェクトの動きだ。
わかりづらいかもしれないが、初動(正確には2回目のイベント)が遅れて、「ダッ、ダダダダ…」みたい感じで動いている。

これを解決するための方法をまとめる。

スムーズに動かない場合の実装


先のgifアニメのコードは以下のとおり。
<div class="container">
  <div class="box"></div>
</div>
const container = document.querySelector('.container');
const box = document.querySelector('.box');

let x = 0;
let y = 0;
document.body.addEventListener('keydown', e => {
 switch (e.key) {
    case 'ArrowUp':
      x -= 10;
      box.style.top = `${x}px`;
      break;
    case 'ArrowDown':
      x += 10;
      box.style.top = `${x}px`;
      break;
    case 'ArrowLeft':
      y -= 10;
      box.style.left = `${y}px`;
      break;
    case 'ArrowRight':
      y += 10;
      box.style.left = `${y}px`;
      break;
  }
});
イベントハンドラ内で座標のアップデートを行うと、1回目と2回目の実行の間に微妙な間がうまれてしまい、スムーズにオブジェクトを移動させることができない。



解決策: スムーズに動かす実装


オブジェクトをスムーズに動かしたい。イメージ的には以下のgifアニメを見てほしい。
おわかりいただけただろうか?

先ほどの動作に比べて初動がスムーズになっているのがわかると思う。

実装は以下のとおり。
const container = document.querySelector('.container');
const box = document.querySelector('.box');

let x = 0;
let y = 0;
let keydown = '';

document.body.addEventListener('keydown', e => {
  keydown = e.key;
});
document.body.addEventListener('keyup', e => {
  keydown = '';
});

const update = () => {
 switch (keydown) {
    case 'ArrowUp':
      x -= 10;
      box.style.top = `${x}px`;
      break;
    case 'ArrowDown':
      x += 10;
      box.style.top = `${x}px`;
      break;
    case 'ArrowLeft':
      y -= 10;
      box.style.left = `${y}px`;
      break;
    case 'ArrowRight':
      y += 10;
      box.style.left = `${y}px`;
      break;
  }
  
  window.requestAnimationFrame(update);
}

window.requestAnimationFrame(update);
addEventListnerではkeydownまたはkeypressの値を取得するだけ。
実際の座標のアップデートはrequestAnimationFrame内で行っている(setTimeoutでも可)

これでキー押しっぱなしでも初動をスムーズにできる。




以上

written by @bc_rikko

0 件のコメント :

コメントを投稿