へびゲームの作り方 — JavaScriptでブラウザゲームを作ろう

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

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

へびゲームは、エサを食べてどんどん長くなるへびを操作するクラシックなゲームです。このチュートリアルでは、JavaScriptでへびゲームを作る方法を学びましょう。配列をキュー(先頭追加・末尾削除)として使うテクニック、グリッドベースの移動、壁や自分自身との衝突判定など、ゲームプログラミングの重要な基礎が身につきます。

グリッドとへびのデータ構造を準備しよう

へびゲームはグリッド(マス目)上で動きます。へびの体は座標の配列で表し、配列の先頭が「頭」です。方向は{x, y}のオブジェクトで管理すると、移動の計算がとてもシンプルになります。

var GRID_SIZE = 20;
var INITIAL_SNAKE_LENGTH = 3;

var DIR = {
  UP:    { x:  0, y: -1 },
  DOWN:  { x:  0, y:  1 },
  LEFT:  { x: -1, y:  0 },
  RIGHT: { x:  1, y:  0 }
};

var snake = [];
var direction = DIR.RIGHT;
var nextDirection = DIR.RIGHT;

function initSnake() {
  snake = [];
  var startX = Math.floor(GRID_SIZE / 2);
  var startY = Math.floor(GRID_SIZE / 2);

  for (var i = 0; i < INITIAL_SNAKE_LENGTH; i++) {
    snake.push({ x: startX - i, y: startY });
  }
  direction = DIR.RIGHT;
  nextDirection = DIR.RIGHT;
}

DIRオブジェクトで4方向を定義しています。nextDirectiondirectionを分けているのは、1フレーム中に複数回キーを押したときに方向が2回変わるのを防ぐためです。へびの初期位置はグリッドの中央に置き、右方向に3マス分の体を作っています。

へびの移動とエサの処理を作ろう

キュー操作で自然な動きを実現

へびの移動は「頭の前に新しいマスを追加し、尻尾のマスを削除する」というキュー操作で実現します。エサを食べたときは尻尾を削除しないことで、へびが1マス長くなります。

function gameStep() {
  direction = nextDirection;

  // 新しい頭の位置を計算
  var head = snake[0];
  var newHead = {
    x: head.x + direction.x,
    y: head.y + direction.y
  };

  // 壁との衝突判定
  if (newHead.x < 0 || newHead.x >= GRID_SIZE ||
      newHead.y < 0 || newHead.y >= GRID_SIZE) {
    gameOver();
    return;
  }

  // 自分自身との衝突判定
  for (var i = 0; i < snake.length - 1; i++) {
    if (snake[i].x === newHead.x && snake[i].y === newHead.y) {
      gameOver();
      return;
    }
  }

  // 頭を追加
  snake.unshift(newHead);

  // エサを食べたかチェック
  if (food && newHead.x === food.x && newHead.y === food.y) {
    score += 1;
    spawnFood();
  } else {
    // 食べなかった → 尻尾を削除
    snake.pop();
  }
}

unshiftで配列の先頭に新しい頭を追加し、popで末尾(尻尾)を削除します。エサを食べたときはpopしないので、へびが1マス伸びるわけです。このシンプルなキュー操作が、へびの「頭が進んで尻尾が追いかける」動きを自然に表現しています。

方向転換と逆走防止を実装しよう

へびゲームでは、現在の進行方向と逆方向に転換できないルールがあります。右に進んでいるときに左を押しても無視する、という処理を実装しましょう。

function changeDirection(newDir) {
  // 逆方向のチェック
  if (direction.x + newDir.x === 0 &&
      direction.y + newDir.y === 0) {
    return; // 逆方向は無視
  }
  nextDirection = newDir;
}

function spawnFood() {
  var occupied = {};
  for (var i = 0; i < snake.length; i++) {
    occupied[snake[i].x + ',' + snake[i].y] = true;
  }

  var emptyCells = [];
  for (var y = 0; y < GRID_SIZE; y++) {
    for (var x = 0; x < GRID_SIZE; x++) {
      if (!occupied[x + ',' + y]) {
        emptyCells.push({ x: x, y: y });
      }
    }
  }

  food = emptyCells[Math.floor(Math.random() * emptyCells.length)];
}

逆方向の判定はdirection.x + newDir.x === 0で行えます。右(1,0)と左(-1,0)を足すと(0,0)になるので逆方向とわかります。エサの配置では、へびが占めているマスを除外して空きマスだけをリストアップし、その中からランダムに選んでいます。へびが全マスを埋めたら勝利です。

まとめ — 次のステップ

このチュートリアルでは、キュー操作によるへびの移動、方向転換と逆走防止、壁と自己衝突の判定の3つを学びました。さらに発展させるなら、壁をすり抜けるワープモード、特殊なエサ(ボーナスポイントや一時的なスピードアップ)、へびの見た目のカスタマイズ機能に挑戦してみましょう。スコアに応じてスピードが上がる仕組みも良い練習になりますよ。

よくある質問

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

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

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

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