バーチャルパッドの実装:親指で押しやすい配置と大きさ
遊びをつくる執筆にClaudeを使用しています。

スマートフォンでブラウザゲームを遊ぶとき、画面上に表示する仮想のボタンやスティック(バーチャルパッド)の出来栄えが操作感を決定的に左右します。「ボタンが小さくて押し間違える」「親指が届かない位置にある」という問題は、ゲームそのものの面白さとは無関係に、プレイヤーをすぐに離脱させます。 この記事では、バーチャルパッドをHTMLとJavaScriptで実装するときに判断が必要な「ボタンの大きさ」「画面上の配置」「タッチ判定の広げ方」の三点を、実装手順と合わせて具体的に説明します。デザイン上の好みではなく、親指の可動域や端末の画面比率から導ける根拠のある基準を示すことを目的にしています。
親指が届く範囲を先に知る
バーチャルパッドの配置を決める前に、スマートフォンを片手持ちしたときに親指が自然に届く領域を把握しておく必要があります。一般に「サムゾーン(Thumb Zone)」と呼ばれるこの概念は、UXデザインの分野で広く参照されています。
縦持ちで片手操作を前提にすると、親指が無理なく届くのは画面下部の約40〜50%の範囲で、左右どちらの手で持つかによって利き側に少し偏ります。画面上半分は「届くが動かしにくい」ゾーン、画面の四隅(特に上の左右)は「届かない」ゾーンです。
ゲームのUIでよく見る十字キーや移動スティックを左下、アクションボタン群を右下に配置する慣習は、このサムゾーンの形状を素直に反映したものです。画面中央や上部にボタンを置いた場合、片手での操作が成立せず、プレイヤーは持ち方を変えるか両手操作を強いられます。
ボタンの大きさと間隔の基準
タップ領域の最小サイズ
Apple のヒューマンインターフェイスガイドラインや Google のマテリアルデザインガイドラインは、タッチターゲットの推奨最小サイズをそれぞれ44×44pt、48×48dpとしています(各ガイドラインの最新値は公式ドキュメントで確認してください)。CSSのピクセル値に換算するとおおむね44〜48px相当ですが、これはUIの一般的な最小値であり、ゲームのバーチャルパッドとしては小さすぎます。
動きながら操作するゲームでは、目線がゲーム画面に向いていて手元を見ずにボタンを押す状況が常態です。この条件ではタップ精度が通常UIより大幅に落ちるため、実用的な最小値は70〜80px、快適な標準値は90〜110pxを目安にしてください。押しやすさよりもゲーム画面の視認性を優先したいジャンル(パズルなど)では下限寄りに、アクションやシューティングでは上限寄りにします。
ボタン間の余白
ボタン同士の間隔が狭いと押し間違いが増えます。隣接するボタンのタップ領域同士が重ならないようにしつつ、指の腹が触れた際にどちらのボタンかを誤認しにくくするために、ボタン間の余白は最低でも10〜12px確保するのが妥当です。CSSで gap プロパティや margin を使って管理すると調整しやすくなります。
視覚的な円とタップ判定の関係
円形のボタンをCSSで描く場合、border-radius: 50% で表示は円になりますが、タップ判定はHTML要素の矩形領域のままです。円の外側の角にも判定が残るため、隣のボタンと判定が重なりやすくなります。これを防ぐには、要素サイズを視覚的な円よりやや小さめにし、PointerEventやTouchEventで取得した座標と円の中心距離を比較して判定する方法が確実です。
// 円形タップ判定の考え方(擬似コード)
const dx = touchX - buttonCenterX;
const dy = touchY - buttonCenterY;
const hit = Math.sqrt(dx * dx + dy * dy) <= radius;この方法を使えば視覚と判定を一致させられ、隣接ボタンとの誤タップも減らせます。
画面サイズへの対応:vw・vhを使った配置
スマートフォンは機種によって画面サイズが異なるため、ピクセル固定でボタンを配置すると小さい端末では窮屈に、大きい端末ではボタンが小さすぎる状態になります。
バーチャルパッドの配置にはビューポート単位(vw・vh)を活用します。たとえば移動スティックを左下に置く場合、次のような考え方で位置を決められます。
- 左端からの距離:left: 5vw 程度。端末の端に近すぎると持ち手の親指の付け根で誤タップしやすいため、数パーセント余白を取ります。
- 下端からの距離:bottom: 8vh 程度。画面最下部はスワイプでブラウザのUIが出る端末もあるため、少し上に逃がします。
- ボタンのサイズ:width: 18vw; height: 18vw のように幅に合わせた正方形にすると、縦長・横長どちらの端末でも比率が保てます。ただし 18vw が実ピクセルで70pxを下回るような小型端末向けには、min-width: 70px でフロアを設けます。
横持ち(landscape)では画面の縦幅が狭くなり、vh ベースのサイズが小さくなりすぎることがあります。@media (orientation: landscape) でサイズや位置を上書きするか、横持ちでは vw の比率を下げて実寸を確保します。
アナログスティックの実装手順
十字ボタンではなくアナログスティック(ジョイスティック)型を実装する場合は、ベース円の中でノブ円がドラッグに追随する仕組みが必要です。手順を整理します。
- HTML構造:ベース円(外側)とノブ円(内側)を二重のdivで作ります。ベース円をposition: relative、ノブ円をposition: absoluteにして、中央揃えをデフォルト状態にします。
- タッチ開始:touchstart または pointerdown でベース円の中心座標を記録します。ベース円のgetBoundingClientRect()を使うと現在の位置を正確に取得できます。
- タッチ移動:touchmove または pointermove でタッチ座標とベース中心の差分を計算し、その差分がベース半径を超えないようにクランプ(制限)してノブ円を移動させます。
// クランプの考え方
const dx = touchX - baseCenterX;
const dy = touchY - baseCenterY;
const dist = Math.sqrt(dx * dx + dy * dy);
const clampedDist = Math.min(dist, baseRadius);
const angle = Math.atan2(dy, dx);
const knobX = Math.cos(angle) * clampedDist;
const knobY = Math.sin(angle) * clampedDist;- 入力値の正規化:knobX / baseRadius と knobY / baseRadius を計算すると、−1〜1の正規化された入力値が得られます。この値をゲームロジックの移動速度に乗算します。
- タッチ終了:touchend または pointerup でノブ円を中心に戻し、入力値をゼロにリセットします。このリセット処理を忘れると、指を離した後も移動し続けるバグになります。
マルチタッチへの対応
左スティックと右のアクションボタンを同時押しするためには、マルチタッチ対応が必須です。TouchEvent の touches または changedTouches には複数の指の情報が含まれています。各タッチに identifier が割り当てられているので、スティックの操作を開始したタッチの identifier を記録し、touchmove の処理時に同じ identifier のタッチだけを追跡します。PointerEvent を使う場合は pointerId が同様の役割を果たします。
実装後に確認すべき失敗パターン
実際に端末で動かすと見落としやすい問題がいくつかあります。
- スクロールの誤発動:バーチャルパッドの操作中に画面がスクロールしてしまう場合は、touchstart や touchmove のイベントハンドラで event.preventDefault() を呼んでいるか確認します。ただし addEventListener に { passive: false } を明示しないと preventDefault() が効かないブラウザがあります。
- フルスクリーンとセーフエリア:iPhoneのホームバーインジケーター付きモデルでは、画面下部にenv(safe-area-inset-bottom)で定義されるセーフエリアがあります。bottom: 8vh に加えて padding-bottom: env(safe-area-inset-bottom) を親要素に設定し、ボタンがホームバーに隠れないようにします。
- コンテキストメニューの抑制:ボタンを長押しするとブラウザのコンテキストメニューが出ることがあります。バーチャルパッドのDOM要素に oncontextmenu="return false" または user-select: none を設定して抑制します。
- ゲームキャンバスへのイベント競合:Canvasと重なる位置にDOMボタンを置く場合、Canvas側でタッチイベントを取得している処理と干渉しないかを確認します。バーチャルパッドをCanvas内で描画する方式にまとめてしまうと競合を避けやすくなります。
次の行動
今回の基準(ボタン70〜110px、下部配置、マルチタッチ対応)をベースにした最小構成のHTMLをローカルで作り、実機のスマートフォンで親指だけで操作できるか確かめてみてください。できあがったゲームはZIPファイルにまとめてアソバース(https://aso-verse.com)に投稿し、スマートフォン向けゲームとして公開できます。実機確認を繰り返すことが、数値の調整よりも早く「押しやすいパッド」に近づく近道です。
参考資料
- Apple ヒューマンインターフェイスガイドライン(Targeting)
- Google マテリアルデザインガイドライン(Accessibility — Touch targets)
- MDN Web Docs — TouchEvent、PointerEvent
- CSS Viewport Units(MDN Web Docs)
- CSS環境変数 env()(MDN Web Docs)

