もぐらたたきの作り方 — JavaScriptでブラウザゲームを作ろう

このゲームで遊ぶ → ソースコード全文 →

このチュートリアルで学べること

もぐらたたきは、穴からランダムに顔を出すもぐらを素早くたたくアクションゲームです。ランダムなタイミングでの出現制御、クリック/タップの判定処理、カウントダウンタイマーの管理など、リアルタイムゲームの基本がまとまって学べる初心者にぴったりのゲームです。

HTMLとCanvasの準備をしよう

もぐらたたきは、DOM要素で3x3の穴を作ります。各穴の中にもぐらの要素を配置し、CSSアニメーションでもぐらが出たり引っ込んだりする演出をつけましょう。まずはゲームの定数と状態変数を用意します。

var GAME_DURATION = 30;            // ゲーム時間(秒)
var SCORE_PER_HIT = 10;            // 1回のヒットで得るスコア
var INITIAL_MOLE_INTERVAL = 1200;  // もぐらの出現間隔(ミリ秒)
var MIN_MOLE_INTERVAL = 500;       // 出現間隔の最小値
var INITIAL_MOLE_DURATION = 1000;  // もぐらがいる時間(ミリ秒)
var MIN_MOLE_DURATION = 450;       // もぐら表示時間の最小値
var HOLE_COUNT = 9;                // 穴の数(3x3)

var score = 0;
var timeLeft = GAME_DURATION;
var gameRunning = false;
var activeMoles = {};   // 現在出ているもぐらの管理
var lastMoleIndex = -1; // 直前に出たもぐらの穴番号

activeMolesオブジェクトで、どの穴にもぐらが出ているかを管理します。lastMoleIndexで前回と同じ穴に連続して出るのを防ぎます。

ランダム出現とタイマー管理を作ろう

もぐらをランダムな穴から出す

もぐらが出る穴をランダムに選びますが、既にもぐらが出ている穴や、直前に出た穴を避けることで、自然な出現パターンになります。時間の経過とともに出現間隔を短くして、難易度を上げましょう。

// ランダムな穴を選ぶ(前回と同じ穴を避ける)
function getRandomHoleIndex() {
  var available = [];
  for (var i = 0; i < HOLE_COUNT; i++) {
    if (!activeMoles[i] && i !== lastMoleIndex) {
      available.push(i);
    }
  }
  if (available.length === 0) return -1;
  return available[Math.floor(Math.random() * available.length)];
}

// 難易度に応じた出現間隔を計算
function getMoleInterval() {
  var elapsed = GAME_DURATION - timeLeft;
  var progress = elapsed / GAME_DURATION;
  var interval = INITIAL_MOLE_INTERVAL
    - (INITIAL_MOLE_INTERVAL - MIN_MOLE_INTERVAL) * progress;
  return Math.max(interval, MIN_MOLE_INTERVAL);
}

progressは0から1に変化する値で、ゲームの経過割合を表します。時間が進むほどintervalが小さくなり、もぐらの出現が速くなります。

もぐらの出現スケジュール

function showMole(index) {
  if (index < 0 || activeMoles[index]) return;
  var mole = moles[index];
  mole.classList.add('active');
  lastMoleIndex = index;

  // 一定時間後にもぐらを引っ込める
  var duration = getMoleDuration();
  activeMoles[index] = setTimeout(function () {
    hideMole(index);
  }, duration);
}

function scheduleMole() {
  if (!gameRunning) return;
  var index = getRandomHoleIndex();
  if (index >= 0) showMole(index);

  // 次のもぐらをスケジュール
  var interval = getMoleInterval();
  moleSpawnTimer = setTimeout(scheduleMole, interval);
}

setTimeoutを使って、もぐらが自動的に引っ込む処理と、次のもぐらの出現を連鎖的にスケジュールします。scheduleMoleが自分自身を再スケジュールすることで、ゲーム中ずっともぐらが出続けます。

クリック判定とスコアを実装しよう

穴をクリック(またはタップ)したとき、そこにもぐらが出ていればヒットとしてスコアを加算します。既にたたかれたもぐらを二重にカウントしないよう、whackedクラスでガードしましょう。

function whackMole(index) {
  if (!gameRunning) return;
  if (!activeMoles[index]) return; // もぐらが出ていない

  var mole = moles[index];
  if (mole.classList.contains('whacked')) return; // 既にたたかれた

  // たたくエフェクト
  mole.classList.add('whacked');

  // スコア加算
  score += SCORE_PER_HIT;
  updateScore();

  // 少し遅延してから引っ込める
  clearTimeout(activeMoles[index]);
  activeMoles[index] = setTimeout(function () {
    hideMole(index);
  }, 300);
}

// 各穴にクリック・タッチイベントを設定
for (var i = 0; i < holes.length; i++) {
  (function (index) {
    holes[index].addEventListener('click', function (e) {
      e.preventDefault();
      whackMole(index);
    });
    holes[index].addEventListener('touchstart', function (e) {
      e.preventDefault();
      whackMole(index);
    }, { passive: false });
  })(i);
}

クロージャ(即時関数)を使って、ループ変数iの値を各イベントハンドラにキャプチャしています。touchstartイベントも追加することで、スマートフォンでも快適に遊べます。

まとめ — 次のステップ

このチュートリアルでは、ランダムな出現制御、クリック判定とスコア管理、動的な難易度変化の仕組みを学びました。さらに発展させるなら、特別なもぐら(たたくとボーナスや減点)、コンボシステム(連続ヒットでボーナス)、もぐらの出現アニメーション強化、難易度選択モードなどを追加してみましょう。

よくある質問

Q: プログラミング初心者でも作れますか?

A: はい、大丈夫です。このチュートリアルではステップごとにコードを書いていくので、初めての方でも順番に進めれば完成できます。わからないところがあれば、ひなテックの教室で質問もできますよ。

Q: どのくらい時間がかかりますか?

A: 基本部分は約30分〜1時間で作れます。見た目をこだわったり機能を追加すると、さらに楽しく発展させられます。