リピートの遅延や間隔はイベントだけでは制御できない。
成果物
keydown, keyup, keypressイベントにおけるリピートの遅延を確認する。
きっかけ
JavaScriptでテトリス作ってみたい。
探してみた
たぶん誰かが作っているだろうと思って探してみた。
意外にもJSで実装されていてサイトで遊べるものが見つからない。上記はCSS3で作られたらしい。JSでないが、すごい。
プレイしてみたが……
入力に問題あり。
長押し時に文字入力用ウェイトが生じてしまい連続移動できない。たとえば→キー押下して右へ連続移動したいが、一マス分移動した直後、しばらく止まってしまう。移動が遅れてゲームオーバーになる。
この待機時間はOSのキーボード入力設定で「リピートの遅延時間」に当たる。また、連続入力される間隔も「リピートの間隔」などで設定する。ミリ秒単位で指定できるはず。Raspbian8.0なら以下のような設定画面になる。
本来、リピートの遅延や間隔はゲーム内で一律に指定すべき。もしOS毎に変わってしまったらゲーム性として致命的な欠陥となる。
長押しの挙動はバラバラ
どうやらJSで長押しするときのイベント発火は、OSやブラウザ毎に挙動が異なるらしい。え、HTML5とかの規格で統一されているんじゃないの……。
http://shain.blog.conextivo.com/2007/03/javascript.html
キーイベント
JSのキーイベントについて仕様を調べてみる。
https://developer.mozilla.org/ja/docs/Web/API/KeyboardEvent
三種類
名前 | 概要 |
---|---|
KeyDown | キーを押した時に発火する |
KeyUp | キーを離した時に発火する |
KeyPress | Ctrlなど修飾キーでなかった場合、キーを押した時に発火する |
auto-repeat
長押しで連続入力される現象を「auto-repeat」と呼ぶらしい。
JSにおけるauto-repeatはOSレベルで制御されるらしい。つまりJSでは制御できない……。
リピート遅延や間隔における時間の仕様もなさそう。ブラウザの実装によって挙動が違うのは仕様がないせいだろう。
確認用サイトを作ってみた
リピート遅延
以下の環境にて、KeyDown, KeyPress, ともにOSで設定したリピート遅延が生じてしまうことが確認できてしまった……。
- Raspberry Pi 3 Model B
リピート遅延が生じてしまうと何がマズイ?
イベント駆動開発できない。
たとえばキー押下時、100ms毎にcounterをインクリメントしたい場合。
以下ではダメ。OSで指定したリピート遅延と間隔の時間が適用されてしまう。
window.document.onkeydown = function(e){ counter++; }
以下のように設定できたら楽だったのになぁ……と妄想した。こんなコードは書けないので注意。
onkeydown.repeat.delay = 1000; // リピート遅延1000ms onkeydown.repeat.interval = 200; // リピート間隔200ms window.document.onkeydown = function(e){ counter++; }
では、どうやってリピート遅延や間隔を制御するのか?
いわゆるゲームループが必要になる。1/60秒ごとに実行するループ文のことだ。
単純化すると、以下のような実装が必要になると思われる。
IsOnKeyA = false; window.document.onkeydown = function(e){ if (e.code == 65) { IsOnKeyA = true; } } window.document.onkeyup = function(e){ if (e.code == 65) { IsOnKeyA = false; } } while (1/60秒ごとに1回実行する) { if (IsOnKeyA) { counter++; } }
これで1/60秒ごとにcounterがインクリメントされる。
これの何が問題かって? イベント駆動で実装できていないことだ。処理を一箇所にまとめられないことだ。
本当はonkeydown
の関数にcounter++;
文を実行させるだけで終わらせたかった。しかし時間制御するためメインループとしてwhile
文を使わざるを得ないため、煩雑なコードになってしまった。
理想としては、以下のようにオブジェクト指向で開発できたら嬉しい。
game.fps = 60; game.loop = function() { if (game.key.down.A) { counter++; } } game.start();
たぶんググれば見つかると思う。「JS ゲーム フレームワーク」とかで。
結論
JSにおけるキーイベントのリピート遅延は、イベントだけでは制御できない。制御用のコードを実装する必要がある。
おまけ
FPS
1秒間における描画回数を「FPS」と言う。「Frame per second」の略。ゲームジャンルのFPS(First Person shooter)とは別。
1秒間に60回描画するなら「FPS:60」と言う。FPS:60もあれば不満なくゲーム体験できるらしい。FPS:30以下は遅く、FPS:120はヌルヌル動くらしい。
しばしばPCの処理速度によって遅くなることがある。また、ディスプレイのHz数にも影響される。
人間が知覚できる光の点滅周期が1秒間に55回以下と言われている。