HTML/CSS/JavaScriptで作成するスネークゲーム

スネークゲーム
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>かわいいスネークゲーム</title>
<style>
  html, body {
    margin: 0; padding: 0;
    background: #ffeef2; /* かわいいピンク系背景 */
    font-family: sans-serif;
    user-select: none;
    overflow: hidden;
  }
  #gameContainer {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    position: relative;
  }
  #gameCanvas {
    background: #fffafc; /* 少し明るい背景色 */
    border: 10px solid #ffcce0;
    border-radius: 20px;
    box-shadow: 0px 0px 20px rgba(255,0,100,0.3);
    margin-top: 20px;
  }
  #info {
    color: #ff66a3;
    font-weight: bold;
    margin-top: 10px;
    text-align: center;
  }
  #score {
    position: absolute;
    top: 10px;
    right: 20px;
    color: #ff66a3;
    font-size: 24px;
    font-weight: bold;
    text-shadow: 1px 1px #ffffff;
  }
  #message {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #ff66a3;
    font-size: 32px;
    font-weight: bold;
    text-shadow: 1px 1px #ffffff;
    pointer-events: none;
    text-align: center;
    white-space: pre;
  }
</style>
</head>
<body>
<div id="gameContainer">
  <canvas id="gameCanvas" width="800" height="600"></canvas>
  <div id="score"></div>
  <div id="message"></div>
  <div id="info">
    <p>スペースキーでスタート / ポーズ</p>
    <p>操作: W↑ A← S↓ D→</p>
  </div>
</div>
<script>
(function() {
  const canvas = document.getElementById('gameCanvas');
  const ctx = canvas.getContext('2d');
  const scoreEl = document.getElementById('score');
  const messageEl = document.getElementById('message');

  // ゲーム設定
  const cellSize = 20;
  const cols = Math.floor(canvas.width / cellSize);
  const rows = Math.floor(canvas.height / cellSize);

  // ゲーム状態
  let snake = [];
  let snakeDir = { x: 0, y: 0 };
  let apple = { x: 0, y: 0 };
  let score = 0;
  let running = false;
  let gameLoop = null;
  let paused = true;

  // 初期化関数
  function init() {
    score = 0;
    snake = [];
    // スネーク初期位置を中央付近に
    const startX = Math.floor(cols/2);
    const startY = Math.floor(rows/2);
    for (let i = 0; i < 5; i++) {
      snake.push({ x: startX - i, y: startY });
    }
    // ランダム初期方向
    const dirs = [{x:0,y:-1},{x:1,y:0},{x:0,y:1},{x:-1,y:0}];
    snakeDir = dirs[Math.floor(Math.random()*dirs.length)];

    placeApple();
    updateScore();
    drawAll();
    paused = true;
    showMessage("スペースキーでスタート");
  }

  function placeApple() {
    let valid = false;
    while (!valid) {
      const x = Math.floor(Math.random()*cols);
      const y = Math.floor(Math.random()*rows);
      if (!snake.some(part => part.x === x && part.y === y)) {
        apple.x = x; apple.y = y;
        valid = true;
      }
    }
  }

  function updateScore() {
    scoreEl.textContent = "スコア: " + score;
  }

  function showMessage(msg) {
    messageEl.textContent = msg;
  }

  function hideMessage() {
    messageEl.textContent = '';
  }

  // キー操作
  document.addEventListener('keydown', function(e) {
    if (e.code === 'Space') {
      if (!running) {
        startGame();
      } else {
        togglePause();
      }
    }
    if (!paused) {
      if (e.key === 'w' && snakeDir.y === 0) {
        snakeDir = {x:0,y:-1};
      } else if (e.key === 's' && snakeDir.y === 0) {
        snakeDir = {x:0,y:1};
      } else if (e.key === 'a' && snakeDir.x === 0) {
        snakeDir = {x:-1,y:0};
      } else if (e.key === 'd' && snakeDir.x === 0) {
        snakeDir = {x:1,y:0};
      }
    }
  });

  function startGame() {
    if (running) return;
    running = true;
    paused = false;
    hideMessage();
    gameLoop = setInterval(gameTick, 100);
  }

  function togglePause() {
    if (!running) return;
    paused = !paused;
    if (paused) {
      clearInterval(gameLoop);
      gameLoop = null;
      showMessage("一時停止中\nスペースキーで再開");
    } else {
      hideMessage();
      gameLoop = setInterval(gameTick, 100);
    }
  }

  function gameTick() {
    update();
    drawAll();
  }

  function update() {
    // 次のヘッド位置
    const head = snake[0];
    const newHead = {
      x: head.x + snakeDir.x,
      y: head.y + snakeDir.y
    };

    // 壁判定(反対側から出るかどうか)
    // 通常はゲームオーバーだが、今回はゲームオーバーにする
    if (newHead.x < 0 || newHead.y < 0 || newHead.x >= cols || newHead.y >= rows) {
      gameOver();
      return;
    }

    // 自分自身に衝突
    if (snake.some((part, index) => index !== 0 && part.x === newHead.x && part.y === newHead.y)) {
      gameOver();
      return;
    }

    snake.unshift(newHead);

    // リンゴを食べたか
    if (newHead.x === apple.x && newHead.y === apple.y) {
      score++;
      updateScore();
      placeApple();
    } else {
      snake.pop();
    }
  }

  function gameOver() {
    clearInterval(gameLoop);
    gameLoop = null;
    running = false;
    paused = true;
    showMessage("ゲームオーバー\nスコア: " + score + "\nスペースキーで再スタート");
    // 再初期化待ち
    init();
  }

  function drawAll() {
    ctx.clearRect(0,0,canvas.width,canvas.height);

    // 背景グリッド(淡い色で)
    ctx.strokeStyle = "#ffe6ee";
    for (let i = 0; i < cols; i++) {
      ctx.beginPath();
      ctx.moveTo(i*cellSize,0);
      ctx.lineTo(i*cellSize,canvas.height);
      ctx.stroke();
    }
    for (let j = 0; j < rows; j++) {
      ctx.beginPath();
      ctx.moveTo(0,j*cellSize);
      ctx.lineTo(canvas.width,j*cellSize);
      ctx.stroke();
    }

    // リンゴ
    // リンゴは赤い丸に
    const appleX = apple.x * cellSize + cellSize/2;
    const appleY = apple.y * cellSize + cellSize/2;
    ctx.fillStyle = "#ff3366";
    ctx.beginPath();
    ctx.arc(appleX, appleY, cellSize/2, 0, Math.PI*2);
    ctx.fill();

    // スネーク
    ctx.fillStyle = "#66cc99";
    for (let i = 0; i < snake.length; i++) {
      const part = snake[i];
      const px = part.x * cellSize;
      const py = part.y * cellSize;

      // 頭は少し濃い色に
      if (i === 0) {
        ctx.fillStyle = "#55bb88";
      } else {
        ctx.fillStyle = "#66cc99";
      }
      ctx.fillRect(px, py, cellSize, cellSize);

      // かわいい装飾(目)
      if (i === 0) {
        ctx.fillStyle = "#000000";
        // 頭向きによって目の位置変える
        let eyeOffsetX1 = 0, eyeOffsetY1 = 0;
        let eyeOffsetX2 = 0, eyeOffsetY2 = 0;
        if (snakeDir.x === 1) { // 右
          eyeOffsetX1 = 5; eyeOffsetY1 = 5;
          eyeOffsetX2 = 5; eyeOffsetY2 = 15;
        } else if (snakeDir.x === -1) { // 左
          eyeOffsetX1 = 15; eyeOffsetY1 = 5;
          eyeOffsetX2 = 15; eyeOffsetY2 = 15;
        } else if (snakeDir.y === 1) { // 下
          eyeOffsetX1 = 5; eyeOffsetY1 = 5;
          eyeOffsetX2 = 15; eyeOffsetY2 = 5;
        } else if (snakeDir.y === -1) { // 上
          eyeOffsetX1 = 5; eyeOffsetY1 = 15;
          eyeOffsetX2 = 15; eyeOffsetY2 = 15;
        } else {
          // 初期方向不明時のデフォルト
          eyeOffsetX1 = 5; eyeOffsetY1 = 5;
          eyeOffsetX2 = 15; eyeOffsetY2 = 5;
        }
        ctx.fillRect(px + eyeOffsetX1, py + eyeOffsetY1, 3, 3);
        ctx.fillRect(px + eyeOffsetX2, py + eyeOffsetY2, 3, 3);
      }
    }
  }

  init();
})();
</script>
</body>
</html>

AIを使ったマーケティング支援、業務効率化や利益率アップお任せください。

御社のお困りごとに寄り添ったAI活用のご提案、支援が可能です。

  • AIの使い方の研修
  • AIを使った名刺読みとりや顧客管理システム(CRM)の導入
  • 集客力の高い(問い合わせ数の多い)Webサイトの構築
  • 効率的なマーケティングの実施
  • プログラムの構築、WordPressのプラグイン開発

業務の効率化やAI活用でお困りでしたらまずはお問い合わせください

    お名前必須

    会社名必須

    メールアドレス必須

    電話番号必須

    お問い合わせ内容必須

    個人情報保護方針への同意必須

    この記事が気に入ったら
    フォローしてね!

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