漢字でGO!はpreventDefaultしろ…という単純な話でもなさそうか
ページを開いてゲーム画面があったら、そこでゲームをやろうとするよね?
漢字でGO!の不親切さ
漢字でGO! は、出題される漢字の読み方などの問題に解答していくゲームであり、Webブラウザ上でプレイすることができる。
Firefox 124.0.1 でプレイしたところ、ある不親切な点がみられた。
このゲームには、ゲームの操作としてスペースキーを押すことを要求される場面が存在する。
たとえば、このメニュー画面では、「次へ」すなわちモードを決定して出題数の選択に移る操作にスペースキーが割り当てられている。
ここでスペースキーを押すと、ブラウザの機能によりページが下にスクロールされ、ゲーム画面が隠れてしまうのである。
この動作は、ゲーム画面をクリックし、ゲームの操作が効く状態でも発生する。
不親切だなあ。
preventDefault の有効性
「漢字でGO!」は、ゲームの操作としてスペースキーを押すと、ブラウザの機能でページがスクロールされてゲーム画面が隠れてしまう不親切設計になっていることがわかった。
ところで、このようなイベントに対してブラウザの機能が動作するのをキャンセルする方法があったはずである。
そう、preventDefault である。
「漢字でGO!」は、ページ内にゲーム画面が iframe で埋め込まれた構造になっている。
簡単なサンプルを作って試してみると、
iframe 内のページをクリックし、スペースキーを押すと、iframe 内のページに対する操作が効く (サンプルでは、数値が1増える) とともに、iframe があるページが下にスクロールされる
iframe 内のページの document で keydown イベント に対し preventDefault を用いると、iframe 内のページに対する操作は効き、かつ iframe 内でスペースキーを押しても iframe があるページがスクロールされなくなった
ことが確認できた。
そう簡単にはいかない可能性
preventDefault を使えばスペースキーを押したときにスクロールされるのを防ぐことができるので、「漢字でGO!」がアップデートされて preventDefault をしてくれるようになるのを祈ろう…といいたいところだが、そんな単純な話ではないかもしれない。
「漢字でGO!」の最初 (のほう) の画面をよく見てみよう。
単に「HTMLの入力フォーム」というだけでなく、「111_InputForm.js」という謎の文字列がついているのである。
この文字列でググると、RPGツクールMV用のプラグインらしいことがわかる。
111 Input Form - 111_InputForm.js - #ツクプラ
さらに、「漢字でGO!」のFAQの記述からも、このゲームはRPGツクールMVを用いて作られているらしいことがわかる。
このような特殊なツールが用いられているとなると、preventDefault の追加が
簡単に (正規ルートで) できる
ハックによりできる
できない (規約による禁止を含む)
のどれになるか、自分にはわからない。
ではどうすればいいか
「漢字でGO!」がアップデートされるのを祈らなくても、現状のままでスペースキーを押してもページがスクロールされなくする方法は、いくつかある。
「大画面でゲームを遊ぶ」を使う
「漢字でGO!」のページ内のゲーム画面の下にある「大画面でゲームを遊ぶ」を押すと、ゲーム画面単体のページを新しいタブで開くことができる。
この新しいタブであれば、スクロールされる余地が無いため、スペースキーを押してもページがスクロールされず、快適にこのゲームをプレーすることができる。
タブを切り離して新しいウィンドウにすれば、ゲーム画面の大きさの調節もできる。
Google Chrome を使う
今回の不親切な挙動は、Firefox でみられるものである。
Google Chrome 123.0.6312.86 で試したところ、「漢字でGO!」および自作サンプル (preventDefault を行わない) の両方で、iframe 内の操作のためにスペースキーを押しても iframe があるページがスクロールされることはなかった。
自作サンプルでもスクロールされなかったことから、「漢字でGO!」側で何か Google Chrome (など) でだけ効く対策を行っているわけではなく、単なるブラウザ間の挙動の違いであると推測できる。
ただし、ブラウザの挙動はブラウザの種類だけでなく、バージョンによっても変わりうることには注意したい。
大きなスクロールを検知して戻す
手元の環境 (Firefox) で試したところ、マウスホイールによるスクロールでは1回で window.scrollY が約 100 変わったのに対し、スペースキーによるスクロールでは1回で window.scrollY が約 700 変わった。
そこで、これらの値の中間をしきい値にして判定を行うことで、マウスホイールによるスクロール (スクロールしたいと仮定する) なのかスペースキーによるスクロール (ゲームの操作を意図しており、スクロールはしたくないと仮定する) なのかを推測することができる。
これを scroll イベント のハンドラーで行い、スペースキーによるスクロールだと推測したらスクロールを戻すことで、今回の不親切な挙動による害を減らすことができる。
実際に、以下のスクリプトを開発者ツールで実行すると、ゲーム内でスペースキーを押したとき、一瞬チラつくもののすぐに戻り、プレイに支障が無い状態になった。
(() => {
let lastY = window.scrollY;
document.addEventListener("scroll", () => {
if (Math.abs(window.scrollY - lastY) > 400) {
window.scroll(window.scrollX, lastY);
} else {
lastY = window.scrollY;
}
});
})()
毎回開発者ツールで手動で実行するかわりに、Greasemonkey のユーザースクリプトとして登録してもよい。
まとめ
「漢字でGO!」がアップデートされて不親切さが解消されてくれたら嬉しいが、アップデートが期待できるかはわからない。
アップデートを期待しすぎず、今回紹介した対処法で不親切さによる害を回避するのがよいだろう。
また、自分が iframe で埋め込まれることを想定したゲームを作る際は、このような不親切さを生まないように preventDefault などによるスクロール対策ができるよう、覚えておきたい。