NFTの使い方 プロダクト紹介

【HTMLのみ】簡易シューティングゲームを作ってみた

ゲームの概要

ここでは、非常に簡単なインベーダーゲームのような遊びができる、シューティングゲームの作り方をご紹介します。下記のゲーム画面のように、遊ぶことができます。

ゲームのプレイはコチラから

スクリーンショット 2023-06-28 20.58.58.png

同梱物

  • index.html(ゲームのメインプログラムです)
  • 背景画像(ゲームの背景となる画像です)
  • 敵オブジェクト(牡蠣の画像です)
  • Playerオブジェクト(忍者の画像です)

仕様

  • 移動:左右の矢印ボタンで移動します(移動は左右のみ)
  • 攻撃:スペースで弾を発射します(押しっぱなしで連続発射も可能)
  • 得点:牡蠣1体撃破につき、+10点
  • 当たり判定:牡蠣との接触では、当たり判定のカウントなし
  • ゲームオーバー:設定なし

ソースコードや同梱物は、Githubへ公開中です(コチラを参照ください)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>KAKI-WARS</title>
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
      background-color: #222;
      background-image: url("back.png");
      background-size: cover;
    }
    canvas {
      border: 1px solid #ffffff;
    }
  </style>
</head>
<body>
  <canvas id="gameCanvas" width="480" height="320"></canvas>
  <script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const keys = {};


    document.addEventListener('keydown', (e) => {
      keys[e.code] = true;

      // 追加: スペースキーが押されたときに弾を発射
      if (e.code === 'Space') {
        player.bullets.push({
          x: player.x + player.size / 2 - 2,
          y: player.y - 10,
          size: 4,
          speed: 6
        });
      }
    });

    document.addEventListener('keyup', (e) => {
      keys[e.code] = false;
    });

    let player = {
      x: canvas.width / 2,
      y: canvas.height - 30 - 30, // 上に30px移動
      size: 60,
      speed: 4,
      bullets: [],
      ready: false
    };

    let enemies = [];
    let enemySpawnCounter = 0;
    let moveDirection = 1;
    let moveDownCounter = 0;
    let score = 0;

    let playerImage = new Image();
    playerImage.src = "忍者-ジャンプ4.png";
    playerImage.onload = function() {
      player.image = playerImage;
      player.ready = true;
    };

    let enemyImage = new Image();
    enemyImage.src = "kaki.png";
    enemyImage.onload = function() {
      for (const enemy of enemies) {
        enemy.image = enemyImage;
        enemy.ready = true;
      }
    };

    function drawEnemies() {
      for (const enemy of enemies) {
        if (enemy.ready) {
          ctx.drawImage(enemy.image, enemy.x, enemy.y, enemy.size, enemy.size);
        }
      }
    }

    function drawBullets() {
      ctx.fillStyle = 'green';
      for (const bullet of player.bullets) {
        ctx.fillRect(bullet.x, bullet.y, bullet.size, bullet.size);
      }
    }

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

      if (player.ready) {
        ctx.drawImage(player.image, player.x, player.y, player.size, player.size);
      }

      drawEnemies();
      drawBullets();

      if (keys['ArrowLeft']) {
        player.x -= player.speed;
      }
      if (keys['ArrowRight']) {
        player.x += player.speed;
      }

      for (const bullet of player.bullets) {
        bullet.y -= bullet.speed;
      }
      player.bullets = player.bullets.filter(bullet => bullet.y > 0);

      // 弾と敵の衝突判定を追加
      player.bullets.forEach((bullet) => {
        enemies.forEach((enemy) => {
          if (
            bullet.x < enemy.x + enemy.size &&
            bullet.x + bullet.size > enemy.x &&
            bullet.y < enemy.y + enemy.size &&
            bullet.y + bullet.size > enemy.y
          ) {
            bullet.toRemove = true;
            enemy.toRemove = true;
            score += 10;
          }
        });
      });

      player.bullets = player.bullets.filter((bullet) => !bullet.toRemove);
      enemies = enemies.filter((enemy) => !enemy.toRemove);

      enemySpawnCounter++;
      if (enemySpawnCounter >= 30) {
        let newEnemy = {
          x: Math.random() * (canvas.width - 20),
          y: 10,
          size: 40,
          speed: 2,
          ready: false
        };
        newEnemy.image = enemyImage;
        newEnemy.ready = true;
        enemies.push(newEnemy);
        enemySpawnCounter = 0;
      }

      moveDownCounter++;
      if (moveDownCounter >= 60) {
        moveDirection = -moveDirection;
        for (const enemy of enemies) {
          enemy.y += 20;
        }
        moveDownCounter = 0;
      }

      for (const enemy of enemies) {
        enemy.x += enemy.speed * moveDirection;
      }
      enemies = enemies.filter(enemy => enemy.y < canvas.height);

      ctx.fillStyle = "white";
      ctx.font = "16px Arial";
      ctx.fillText("Score: " + score, 10, 20);

      requestAnimationFrame(update);
    }

    canvas.addEventListener('click', (e) => {
      player.bullets.push({
        x: player.x + player.size / 2 - 2,
        y: player.y - 10,
        size: 4,
        speed: 6
      });
    });

    update();
  </script>
</body>
</html>

ゲームパッケージ

最後に…「KAKI WARS」ということで、あの懐かしいゲームの外箱っぽいデザインに仕上げてみました。もちろん、パッケージは存在しないので、架空の外箱となります。

NINJA 牡蠣.png
ハイクラス求人 ビズリーチ
ぬるぺでぃあ

A. Miura

通称「みうらドーナツ」。本業はRPA/DX系のSEであり、ねじねじドーナツ部長の作者でもある。大好きなドーナツにハマってしまい、ドーナツとの共同生活を送っている「部長」さんの日常をNFT化する日々を送る。

「ぬるぺでぃあ」の更新通知を受け取ろう!

下記「購読」ボタンより、このブログの更新情報を受け取ることができます。(※「購読」と書かれていますが、無料で利用可能です。また購読には、メールアドレスの入力が必要ですが、入力いただいたメールアドレスは、更新情報の通知の目的以外には使用しません)

-NFTの使い方, プロダクト紹介