マガジン

レスポンシブなゲーム画面:PC・タブレット・スマホを1本で

遊びをつくる

執筆にClaudeを使用しています。

絵の具で描いた動きと紙のカード型部品を、一つの駒がつなぐコラージュ
記事のテーマをもとに制作したAI生成イラスト。

ブラウザゲームを作っていて「PCでは綺麗なのにスマホで見たら崩れていた」という経験は珍しくありません。ゲームの場合、通常のWebページと違って画面全体をキャンバスとして使うことが多く、CSSだけで済む話にならないことが多いです。 この記事では「1本のHTMLで複数デバイスを同時に対応する」ための考え方と、実装の判断基準を整理します。「レスポンシブデザイン」という言葉はWebの文脈で広く使われますが、ゲーム画面に適用するときはいくつか別の注意点があります。それを具体的に示します。

この記事の目次
  1. ゲーム画面のレスポンシブが難しい理由
  2. まず「どのアスペクト比を基準にするか」を決める
  3. Canvasを使う場合の実装パターン
  4. DOMベースのゲームの場合
  5. 失敗しやすいポイントと確認の順序
  6. 次の行動
  7. 参考資料

ゲーム画面のレスポンシブが難しい理由

Webページのレスポンシブは「テキストを折り返す・画像を縮小する」が中心です。しかしゲーム画面は縦横比(アスペクト比)を崩すとゲームが成立しなくなることがあります。たとえば「3×3マスのパズル」を作るとき、マスが横長になれば当たり判定がズレます。「スプライトを16:9の領域に配置している」なら、9:16のスマホ縦持ちで表示すると上下が余るか、左右が切れます。

もうひとつの難しさは入力方式の違いです。PCではマウスクリック、スマホではタッチ。タップ領域が小さすぎると操作しづらく、逆に大きすぎるとPCでは邪魔です。レイアウトと入力の両方を同時に解決する必要があります。

さらにパフォーマンスの差があります。PCでは60fpsで動くCanvas描画が、ミドルレンジのAndroidスマホでは重くなることがあります。レスポンシブ対応の中でこの点を忘れると、見た目は整っても動作が粗いゲームになります。

まず「どのアスペクト比を基準にするか」を決める

実装を始める前に、ゲームの論理解像度(内部座標系のサイズ)を決めることが最初のステップです。ここを曖昧にすると、後からすべての調整が困難になります。

判断の目安:

  • アクション・パズル・RPGなど横長のゲームは 16:9(例:1280×720)が扱いやすいです。PCのフルスクリーンと相性がよく、スマホ横持ちでもそのまま使えます。
  • カード・ボードゲームやスマホ縦持ちを主戦場にするゲームは 9:16 あるいは 3:4 を基準にする方が自然です。
  • マス目・盤面系(オセロ・チェス・パズルなど)は 1:1 にして、余白で調整するのが最もシンプルです。

論理解像度を決めたら、それを「実際の画面サイズにどう収めるか」という問題だけに集中できます。

Canvasを使う場合の実装パターン

HTML Canvasを使うゲームでの基本的な対応手順を示します。

1. Canvasの論理サイズと表示サイズを分離する

html
<canvas id="game" width="1280" height="720"></canvas>

width / height 属性は内部の描画解像度(論理サイズ)を決めます。これは変更しません。CSSで表示サイズだけを変えます。

css
#game {
  display: block;
  width: 100%;
  max-width: 1280px;
  height: auto;
}

height: auto にすることでアスペクト比が維持されたまま、画面幅に追従します。これだけで多くのケースはPCとスマホ横持ちに対応できます。

2. 縦持ちスマホへの対応:letterboxを使う

スマホの縦持ち(portrait)では画面幅が狭く、16:9のゲームは大幅に縮小されます。プレイしにくい場合は「横持ちを促すUI」を出す方法がシンプルです。

css
@media (orientation: portrait) and (max-width: 600px) {
  #rotate-notice {
    display: flex; /* 「横に回してください」案内 */
  }
  #game {
    display: none;
  }
}

縦持ちでもプレイさせたい場合は、画面に収まるよう上下または左右に余白(letterbox)を置いて中央に表示します。JavaScriptで実装する場合は次のような計算をします。

javascript
function fitCanvas() {
  const canvas = document.getElementById('game');
  const scaleX = window.innerWidth / 1280;
  const scaleY = window.innerHeight / 720;
  const scale = Math.min(scaleX, scaleY);
  canvas.style.width = (1280 * scale) + 'px';
  canvas.style.height = (720 * scale) + 'px';
}
window.addEventListener('resize', fitCanvas);
fitCanvas();

Math.min でアスペクト比を崩さず、かつ画面からはみ出さない最大サイズを求めています。

3. タッチとマウスを同時に扱う

ゲームのクリック処理を addEventListener('click', ...) だけで実装していると、スマホで300ms前後の遅延が発生することがあります。タッチイベントも並べて実装するか、pointer events(PointerEvent API)を使うと両方をまとめて扱えます。

javascript
canvas.addEventListener('pointerdown', (e) => {
  const rect = canvas.getBoundingClientRect();
  const scaleX = 1280 / rect.width;
  const scaleY = 720 / rect.height;
  const x = (e.clientX - rect.left) * scaleX;
  const y = (e.clientY - rect.top) * scaleY;
  // xとyは論理座標系の値
});

getBoundingClientRect() で取得した表示サイズと論理サイズの比率をかけることで、表示サイズが変わっても論理座標でゲーム内の当たり判定が正確に動きます。これを省くと、スマホで縮小表示したときにタップ位置がズレる典型的なバグになります。

DOMベースのゲームの場合

PhaserやPixiなどを使わず、HTMLの要素(div・button・img)でゲームを作る場合は、CSSのFlexboxやGridが主な手段になります。この場合もアスペクト比の固定が課題です。

CSSの aspect-ratio プロパティを使うと、コンテナのサイズが変わっても比率を維持できます。

css
.game-board {
  aspect-ratio: 1 / 1;
  width: min(90vw, 90vh);
  margin: auto;
}

min(90vw, 90vh) は縦横どちらが短くても90%に収まるサイズを計算します。縦持ちスマホでも横持ちPCでも、盤面が画面からはみ出さず中央に収まります。ボードゲームや1:1の盤面を持つゲームに向いています。

ボタンやUI要素のタップ領域は最低44px×44pxを目安にすると、スマホでも誤タップが減ります。PCでは少し大きく見えても違和感は出にくいため、両対応の場合はモバイルの基準を採用する方が安全です。

失敗しやすいポイントと確認の順序

実際に作り始めてから詰まりやすい点を、確認の順序とともに挙げます。

  1. 最初にスマホで確認する:PCで作りながらスマホを後回しにすると、修正が重なります。ChromeのDevToolsでデバイスエミュレーションを使い、375px幅(iPhoneサイズ)での表示を最初の段階から確認する習慣をつけると見落としが減ります。
  1. フォントサイズをpxで固定しない:スコア表示やメッセージを font-size: 24px のように固定すると、画面が縮小されたときにCanvasの描画と比べてアンバランスになります。Canvasに文字を描くなら論理座標系での相対サイズを使い、DOMに文字を置くなら em か vw を使います。
  1. viewport metaタグを確認する:<meta name="viewport" content="width=device-width, initial-scale=1"> がないと、スマホがページをデスクトップ幅として解釈して縮小表示します。レスポンシブ対応の前提となるタグです。
  1. resize イベントは重くなりやすい:resize ごとに複雑な再計算をするとパフォーマンスが落ちます。requestAnimationFrame でスロットルするか、画面サイズが大きく変わったときだけ処理するよう条件を入れると安心です。
  1. 縦スクロールを意図せず発生させない:height: 100vh の使い方を誤るとスマホのブラウザUIの高さ分がずれ、ゲームが画面外に収まらなくなることがあります。100dvh(dynamic viewport height)の利用も選択肢のひとつですが、対応ブラウザを公式ドキュメントで確認してから使いましょう。

次の行動

まず自分のゲームのアスペクト比を決め、論理解像度をCanvasのwidth/height属性かCSS aspect-ratioで固定するところから始めてください。次に pointerdown イベントで座標を論理座標系に変換する処理を入れると、スマホでの当たり判定ズレを防げます。完成したゲームはZIPまたは単一HTMLとしてアソバースへ投稿し、実際のスマホとPCで動作を確認してみましょう。

参考資料

  • MDN Web Docs — Canvas API
  • MDN Web Docs — Pointer Events
  • MDN Web Docs — CSS aspect-ratio
  • W3C — Viewport meta tag