JavaScript で作る簡単なブラウザゲーム入門:副業エンジニアが語る学習ロードマップと実践手順

目次

はじめに ─ 三十代エンジニアの挑戦とゲーム開発との出会い

私は 10 年以上、Web 制作やサーバー保守の仕事をしてきました。仕事も安定していて収入もそこそこ良かったんですが、いつか自分のアイデアを形にできるような副業をやってみたいと思っていました。そんな時、友達の子どもがブラウザで簡単なゲームをしているのを見て「これなら JavaScript だけで作れるかも」と思ったんです。

昔、ファミコンの『ブロック崩し』にハマっていたのを思い出し、またワクワクしてきたんですよね。

でも、作り始めるとなると、ちょっと不安になりました。ゲーム開発って Unity とか Unreal Engine みたいな専門ツールが必要そうだし、数学の知識もいるって聞くじゃないですか。プログラミングスクールにも「ゲーム制作コース」があったけど、副業のためにそこまでお金をかけるべきか悩んで、とりあえず自分で勉強することにしました。そんな時、Web ブラウザで動く簡単なゲームの作り方を解説している記事を見つけて、HTML・CSS・JavaScript だけでゲームが作れると知ったんです。これが、この記事を書くきっかけになりました。

最初の壁 ─ ゲーム開発初心者がハマる落とし穴

ブラウザゲームに挑戦しようとする人がまず困るのが「何から始めればいいかわからない」ってことだと思います。フレームワークとかライブラリを使うと便利だけど、基本を理解しないままツールに頼ると、応用がきかないんですよね。いきなり Phaser とか Unity に手を出して、挫折した人も周りに何人かいました。副業にするなら、自由にカスタマイズできるスキルが大事なので、最初は JavaScript でしっかり基礎を身につけるのがおすすめです。

あと、「目標がハッキリしてないと、やる気が続かない」ってのもありますね。ゲーム制作は、すぐに結果が見えるから楽しいけど、プログラムがうまく動かない時とか、バグが出た時は、結構大変です。自分ひとりで勉強するなら、最初に学習計画を立てて、どこでつまずきそうかを知っておくと安心です。副業の仕事だと、納期とか品質が求められるので、早いうちから実践的な練習をしておくことも大事です。

初めてゲームを作ってみて、Web 制作とかサーバー保守の仕事とは違う頭の使い方をするなと感じました。特に難しかったのが、画面を何度も書き換える「ゲームループ」の考え方と、ボールが壁に当たった時の反射の処理です。基本をちゃんと理解しないままコードをコピーして貼り付けただけだと、なぜ動くのかわからなくて、そこで終わっちゃいます。次の章からは、同じように悩んでいる人のために、初心者でもわかりやすい学習ロードマップとゲーム制作の手順を紹介していきます。

自宅のリビングでパソコンに向かい、初めてのゲーム開発にわくわくしながら取り組む男性の線画イラスト

解決方法 ─ JavaScript だけで作るブラウザゲームの基本

学習ロードマップ ─ HTML・CSS・JavaScript の基本からゲーム制作へ

まず覚えておきたいのは、ゲーム制作も Web 制作の仲間だということです。ブラウザゲームは、HTML で画面を作って、CSS で見た目を整えて、JavaScript で動きをつける、Web の基本技術を組み合わせたものなんです。初心者がステップアップするためのロードマップをまとめてみました。

  1. HTML と CSS の基本を覚える:まずは<div>タグとか Flexbox、色の指定とか、基本的なことを覚えて、簡単な Web ページを作れるようにしましょう。ゲームでも、UI を作る時に CSS の知識が役に立ちます。
  2. JavaScript の基本を理解する:変数、関数、配列、オブジェクト、イベント処理など、基本的な書き方を勉強します。公式ドキュメントとかオンラインの講座で、ES6 以降の書き方に慣れておくと後々楽になります。
  3. Canvas API に触れてみる:ブラウザゲームでは HTML の<canvas>要素を使って、JavaScript から 2D グラフィックを描きます。例えば、<canvas id="myCanvas" width="480" height="320"> のように HTML にキャンバスを配置して、JavaScript で</canvas></canvas>document.getElementById('myCanvas')getContext('2d')を呼んで描画できるようにします。
  4. ゲームループとアニメーションを理解する:ゲームは、毎回画面を書き換える必要があるので、setInterval()とかrequestAnimationFrame()を使って何度も繰り返す処理を作ります。requestAnimationFrame()を使うと、ブラウザが次に画面を書き換えるタイミングで処理してくれるので、setInterval()よりスムーズにアニメーションできます。
  5. 入力処理や衝突判定を作る:キーボードやマウスの操作に合わせてキャラクターを動かしたり、壁や他のキャラクターとの衝突を検知する方法を勉強します。ボールの場所がキャンバスの端っこまで来たら、ボールの速度を逆にする(マイナスにする)と、壁に当たって跳ね返る動きが作れます。
  6. スコアやゲームオーバーなどのルールを作る:最後に、点数の計算とか、ゲームの勝ち負けの条件を決めて、ゲームを完成させます。作ったゲームは、自分の作品として公開したり、副業の仕事に応募する時にアピールポイントとして使えます。

このロードマップにそって進めれば、ゲーム制作の基本をしっかり身につけることができます。自分ひとりで勉強するのが不安な場合は、プログラミングスクールのオンラインコースを利用したり、詳しい人に質問したりするのもいいと思います。私は、仕事をしながら副業でゲーム制作に挑戦したので、週に 2 回ほどスクールのメンターに相談して、難しいところを乗り越えました。

プロジェクト準備 ─ HTML と CSS でゲームの舞台を作る

基本を覚えたら、実際にゲームを作ってみましょう。「ブロック崩し」とか「スネークゲーム」みたいな簡単なゲームをイメージしています。まずは HTML でキャンバスを用意して、CSS で見た目を整えます。

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width," initial-scale="1.0">
  <title>簡単ブラウザゲーム</title>
  &lt;style&gt;
    /* Canvasを真ん中に配置して、背景色を設定 */
    body {
      margin: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background-color: #f0f4f8;
      font-family: sans-serif;
    }
    #gameCanvas {
      border: 1px solid #333;
      background-color: #fff;
    }



  <!-- ゲーム画面になるCanvas要素 -->
  <canvas id="gameCanvas" width="600" height="400"></canvas>

  <!-- JavaScriptファイルでゲームの動きを記述 -->
  <script src="game.js"></script>

ここでは、<canvas>要素を用意して、幅と高さを設定して、枠線をつけています。キャンバスを真ん中に配置するために、CSS の Flexbox を使ってbody要素を調整しています。次に、JavaScript ファイルgame.jsでゲームの動きを作っていきます。

キャンバスとコンテキストの準備 ─ 図形を描画する

ゲームを描くには、キャンバスと 2D 描画コンテキストを用意する必要があります。

// キャンバス要素と2Dコンテキストを取得
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// ボールの初期位置と速度
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 2; // x方向の速度
let dy = -2; // y方向の速度(上向きに進む)

// ボールの半径
const ballRadius = 10;

// ボールを描画する関数
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
  ctx.fillStyle = '#0095DD';
  ctx.fill();
  ctx.closePath();
}

// 毎フレーム呼び出されるゲームループ
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height); // キャンバスをクリア
  drawBall();

  // ボールの位置を更新
  x += dx;
  y += dy;

  // 壁との衝突判定:左右の壁
  if (x + dx &gt; canvas.width - ballRadius || x + dx &lt; ballRadius) {
    dx = -dx;
  }
  // 上下の壁
  if (y + dy &lt; ballRadius || y + dy &gt; canvas.height - ballRadius) {
    dy = -dy;
  }
}

// requestAnimationFrameを使ったループ
function gameLoop() {
  draw();
  requestAnimationFrame(gameLoop);
}

// ゲーム開始
gameLoop();

このコードでは、getContext('2d')で 2D 描画コンテキストを取得して、beginPath()とかarc()を使って円を描いています。draw()関数ではclearRect()でキャンバスをクリアした後、ボールを描画して、場所を移動します。壁に当たったかの判定には、ボールの半径を考慮していて、画面の端まで来たら速度の符号を逆にするようにしています。最後にrequestAnimationFrame()を使ってループを実行することで、ブラウザの画面書き換えのタイミングに合わせて、スムーズにアニメーションさせています。このように、ゲームループと、物の移動・衝突処理が基本になります。

カフェでノートPCに向かい、ゲームの基本ロジックを学びながら悩む女性の線画イラスト

入力処理 ─ キーボードでパドルを動かす

ブロック崩しみたいなゲームでは、ボールを跳ね返すためのパドルが必要ですよね。次のコードは、パドルを描いて、矢印キーで左右に動かす方法です。

// パドルのサイズと初期位置
const paddleHeight = 10;
const paddleWidth = 75;
let paddleX = (canvas.width - paddleWidth) / 2;

// キーが押されているかどうかの状態
let rightPressed = false;
let leftPressed = false;

// パドルを描画する関数
function drawPaddle() {
  ctx.beginPath();
  ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
  ctx.fillStyle = '#0095DD';
  ctx.fill();
  ctx.closePath();
}

// キーが押された時の処理
function keyDownHandler(e) {
  if (e.key === 'Right' || e.key === 'ArrowRight') {
    rightPressed = true;
  } else if (e.key === 'Left' || e.key === 'ArrowLeft') {
    leftPressed = true;
  }
}

// キーが離された時の処理
function keyUpHandler(e) {
  if (e.key === 'Right' || e.key === 'ArrowRight') {
    rightPressed = false;
  } else if (e.key === 'Left' || e.key === 'ArrowLeft') {
    leftPressed = false;
  }
}

// イベントリスナーの登録
document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);

// draw()関数にパドルの移動と描画を追加
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  drawPaddle();
  // ボール位置の更新(省略)

  // パドルの移動制御
  if (rightPressed &amp;&amp; paddleX &lt; canvas.width - paddleWidth) {
    paddleX += 7;
  } else if (leftPressed &amp;&amp; paddleX &gt; 0) {
    paddleX -= 7;
  }
}

// その他のコードは前述と同じ

このコードでは、keydownkeyupイベントで矢印キーが押されたかどうかをチェックして、毎回パドルの場所を更新しています。左右の端まで来たら、それ以上進まないように条件分岐を入れているのがポイントです。ゲームループでは、ボールとパドルを描画した後、押されているキーに合わせてpaddleXを増やしたり減らしたりします。こうすることで、キーボードの矢印キーを押すとパドルが動くようになります。

衝突判定とブロック崩し ─ 当たり判定を作る

ゲームを面白くするために、ボールがブロックに当たるとブロックが消える処理を追加してみましょう。

// ブロック配置の設定
const brickRowCount = 3;
const brickColumnCount = 5;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;

// ブロックの状態を格納する配列
const bricks = [];
for (let c = 0; c &lt; brickColumnCount; c++) {
  bricks[c] = [];
  for (let r = 0; r &lt; brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0, status: 1 };
  }
}

// ブロックを描画する関数
function drawBricks() {
  for (let c = 0; c &lt; brickColumnCount; c++) {
    for (let r = 0; r &lt; brickRowCount; r++) {
      if (bricks[c][r].status === 1) {
        const brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
        const brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
        bricks[c][r].x = brickX;
        bricks[c][r].y = brickY;
        ctx.beginPath();
        ctx.rect(brickX, brickY, brickWidth, brickHeight);
        ctx.fillStyle = '#0095DD';
        ctx.fill();
        ctx.closePath();
      }
    }
  }
}

// 衝突判定の関数
function collisionDetection() {
  for (let c = 0; c &lt; brickColumnCount; c++) {
    for (let r = 0; r &lt; brickRowCount; r++) {
      const b = bricks[c][r];
      if (b.status === 1) {
        // ボールの中心がブロックの範囲内かを判定
        if (x &gt; b.x &amp;&amp; x &lt; b.x + brickWidth &amp;&amp; y &gt; b.y &amp;&amp; y &lt; b.y + brickHeight) {
          dy = -dy; // ボールの向きを反転
          b.status = 0; // ブロックを消す
        }
      }
    }
  }
}

// draw()関数内で呼び出す
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBricks();
  drawBall();
  drawPaddle();
  collisionDetection();
  // そのほかの処理(ボールの移動、パドルの移動など)
}

このコードでは、ブロックを 2 次元配列で管理して、それぞれのブロックにstatusという状態を表すプロパティを追加しています。status1のブロックだけを描画して、ボールが当たったらdyの符号を逆にして、status0に変えることで、ブロックを消しています。これは簡単な方法ですが、初心者が衝突判定の基本を理解するには十分だと思います。

コワーキングスペースでホワイトボードを使いながらゲームロジックを相談している男女の線画イラスト

スコア計算とゲーム終了条件 ─ ゲームの目的を作る

ブロック崩しでは、全部のブロックを壊すと勝ち、ボールが画面の下に落ちると負け、というルールを作ることができます。簡単なスコア計算を追加して、クリアした時とかゲームオーバーになった時にメッセージを表示するようにすると、もっと楽しくなります。

let score = 0;
let lives = 3;

function drawScore() {
  ctx.font = '16px Arial';
  ctx.fillStyle = '#333';
  ctx.fillText('Score: ' + score, 8, 20);
}

function drawLives() {
  ctx.font = '16px Arial';
  ctx.fillStyle = '#333';
  ctx.fillText('Lives: ' + lives, canvas.width - 65, 20);
}

function collisionDetection() {
  for (let c = 0; c &lt; brickColumnCount; c++) {
    for (let r = 0; r &lt; brickRowCount; r++) {
      const b = bricks[c][r];
      if (b.status === 1) {
        if (x &gt; b.x &amp;&amp; x &lt; b.x + brickWidth &amp;&amp; y &gt; b.y &amp;&amp; y &lt; b.y + brickHeight) {
          dy = -dy;
          b.status = 0;
          score++;
          // 全てのブロックを壊したかチェック
          if (score === brickRowCount * brickColumnCount) {
            alert('クリア!おめでとうございます!');
            document.location.reload();
          }
        }
      }
    }
  }
}

// draw()関数内でスコアとライフを描画
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBricks();
  drawBall();
  drawPaddle();
  drawScore();
  drawLives();
  collisionDetection();
  // ボールが下に落ちた場合
  if (y + dy &gt; canvas.height - ballRadius) {
    lives--;
    if (!lives) {
      alert('ゲームオーバー');
      document.location.reload();
    } else {
      x = canvas.width / 2;
      y = canvas.height - 30;
      dx = 2;
      dy = -2;
      paddleX = (canvas.width - paddleWidth) / 2;
    }
  }
  // パドルの移動処理など
}

スコアとライフの表示は、fillText()を使ってキャンバスに文字を描画することで簡単に作れます。ゲームが終わる条件をハッキリさせることで、遊ぶ意味が明確になって、もっと楽しめます。こういう機能を追加する時も、少しずつコードを分けて、関数ごとに役割をハッキリさせることで、修正しやすくなります。

もう一工夫 ─ 音やエフェクト、スマホ対応

ここまで作れば、もう十分ブラウザゲームとして遊べますが、さらに工夫すると、もっと面白くなります。例えば、ブロックを壊した時とか、ボールがパドルに当たった時に効果音を鳴らしたり、ブロックの色をランダムに変えたりして、見た目をもっと楽しくしたり。効果音は、Audioオブジェクトを使えば簡単に追加できます。最近は、スマホで遊べるゲームの需要も高いので、スマホでも操作できるようにすると、もっと良くなります。touchstartとかtouchmoveイベントを使えば、指の位置に合わせてパドルを動かすことができます。こういう細かい工夫が、お客さんの評価につながります。

自宅のデスクでテストプレイをしながらキーボード操作を確認している若手エンジニアの線画イラスト

実践アドバイス ─ メンター目線で伝える現場のコツ

エラーとデバッグとの向き合い方

初めてゲームを作っていると、画面が真っ白になったり、ボールが急に消えてしまったり、必ず何かしら問題が起こります。私も、ctx変数のスペルを間違えて「cannot read property of undefined」って怒られたことがあります。そんな時は、あせらずに、コンソールにエラーメッセージを表示して、問題がどこにあるのかを探しましょう。console.log()をたくさん使って、変数の値を確認する習慣をつけたり、分割代入とかテンプレート文字列を使うと、デバッグしやすいコードが書けます。

あと、アニメーションの処理では、setInterval()よりrequestAnimationFrame()を使う方が、動きがスムーズになって効率が良いです。ブラウザの画面書き換えにあわせて処理が行われるので、パソコンにかかる負担が少なくなり、省エネにもつながります。ゲーム制作の現場では、こういう細かい調整が、品質に大きく影響します。

コード整理とコメントの重要性

副業の仕事では、他のエンジニアと一緒に作業することも多いので、読みやすいコードを書くように心がけましょう。関数は、一つの目的だけに集中させて、変数名とか関数名には、意味がわかる名前をつけましょう。あと、初めてコードを読む人にもわかりやすいように、コメントを書いておくことが大切です。今回のコード例でも、どこでボールを描画しているのか、どの部分が衝突判定の処理なのか、コメントで書いておくことで、後から見返した時に理解しやすくなります。プログラミングスクールの課題でもコードレビューがあるんですが、コメントがあるかないかで、評価が全然違いました。

ポートフォリオとしての価値を高める

作ったゲームは、GitHub に公開して、自分の作品としてアピールしましょう。リポジトリの README には、ゲームの説明とか、使った技術、苦労した点、学んだことなどを書いて、実際にゲームが遊べるようにデモページへのリンクをはっておくと、見ている人にアピールできます。また、ゲームを改良しながらバージョン管理の練習をすることで、仕事に近い形でスキルを磨くことができます。副業案件では「過去に作った実績」が重視されるので、簡単なゲームでも、自分で最初から作ったゲームは大きな武器になります。

時間管理と体調管理が大切

副業をしながら勉強する場合、時間管理がすごく大切になります。私も、夜遅くまでコードを書いていたら、次の日の仕事に影響が出てしまったことがありました。効率よく進めるには、毎日少しずつでもいいので、続けること、作業を細かく分けて TODO リストを作ることが大事です。あと、長時間同じ姿勢で作業すると、肩が凝ったり、腱鞘炎になったりするので、適度に休憩を取って、ストレッチをするなど、体調にも気をつけながら勉強を続けましょう。

深夜の部屋でゲームのバグを修正しながらも集中している中年エンジニアの線画イラスト

よくある質問

Q1: JavaScript だけで本格的なゲームは作れますか?

A: 作れます。JavaScript と Canvas API とか WebGL を使えば高度なゲームも作れます。ただ、大きいゲームを作る場合は、フレームワークとかライブラリを使った方が効率的です。まずは今回紹介したような簡単なゲームで基本を身につけてから、Phaser とか PixiJS などのライブラリに挑戦するのがいいと思います。

Q2: プログラミングスクールではブラウザゲーム制作を教えてくれますか?

A: 多くのスクールで、JavaScript や Canvas を使ったゲーム制作を教えています。特に副業支援をしているスクールでは、自分の作品を作る練習として、簡単なゲーム開発を取り入れていることが多いです。教材とかメンターから直接アドバイスをもらえるので、自分だけで勉強するより、短い時間で効率的に学べます。

Q3: 副業でブラウザゲームを収益化できますか?

A: 広告収入とか、ゲーム内課金でお金を稼ぐこともできますが、たくさんの人に遊んでもらう必要があります。副業としては、ゲーム制作のスキルを活かして、Web 制作の仕事とか、教育関係の仕事を受ける方が、安定した収入につながると思います。作ったゲームを「サンプル」としてクライアントに見せると、評価が高くなることが多いです。

Q4: ゲーム制作でつまずきやすいところはどこですか?

A: よくあるのは、キャンバスの準備、ゲームループの作り方、キーボードやマウスの操作、衝突判定の実装です。特に衝突判定では、ボールの中心とオブジェクトの範囲を正しく比較することが重要です。エラーが出たら、一度処理を分解して、変数の値をログに出力して、原因を探すようにするといいでしょう。

Q5: このゲームを改造して、スマホでも遊べるようにしたい場合は?

A: touchstarttouchmoveイベントを使って、指の位置に合わせてパドルを動かす処理を追加できます。スマホの画面サイズに合わせて、キャンバスの大きさや文字のサイズを調整すると、より快適に遊べるようになります。スマホに対応した Web サイトを作るための CSS を勉強しておくと役に立ちます。

ゲーム制作から広がる学習と副業の可能性

私の経験をもとに、HTML・CSS・JavaScript の基礎学習から、ゲームループ、パドルの操作、衝突判定、スコア計算まで、順番に説明しました。副業を目指すエンジニアにとって、簡単なゲームを作ることは、自分の作品を増やせるだけでなく、プログラミングの楽しさを改めて感じられる、いい機会になると思います。

ゲームを作ってみて気づいたことの一つは、遠回りに見える基礎学習が、実は一番効率的な方法だということです。便利なライブラリとかフレームワークを使う前に、JavaScript だけで動く仕組みを理解すると、応用力が全然違ってきます。それに、エラーとかバグにぶつかった時の試行錯誤は、スクールの授業では得られない、貴重な経験になります。

副業では、短い時間で結果を出すことが求められます。ブラウザゲームのような小さなプロジェクトで、計画から、開発、デバッグ、公開まで、自分で一通り経験することは、本業でも役に立ちます。――そんな話を友人にすると「自分にもできるかな?」と目をキラキラさせていました。

完成したゲームを友人たちとテストプレイして笑い合う男女の線画イラスト

完成したゲームをみんなで遊ぶ時間は、本当に楽しいです。みんなで笑い合う時間は、ゲームを作るために何ヶ月も頑張った自分へのご褒美です。でも、本当に大切なのは、そこがゴールじゃないってことです。ゲーム制作を通して身につけた、考える力とか、問題を解決する力、そしてあきらめない気持ちは、副業の仕事を見つけたり、本業の仕事をこなす上で、必ず役に立ちます。

あなたも今日から、紙とペンを持って、アイデアを書き出して、ブラウザに小さなゲームを描いてみませんか?どんな小さなアイデアでもいいんです。作りながら学ぶうちに、自分の苦手なこととか、新しい興味が見えてきます。きっと、自分の手で動くものを作る喜びに気づいて、新しい副業への扉を開くきっかけになるはずです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いたエンジニア

小林 朋子のアバター 小林 朋子 アプリケーションエンジニア

アプリケーション開発に精通したエンジニアで、丁寧な設計と柔軟な対応力が強み。親しみやすい性格で、周囲を自然と明るくするタイプ。休日は映画鑑賞やカフェでのんびりするのが好き。バランス感覚に優れた安定感のある人物。

目次