2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptでツリーランゲームを作ってみた

Posted at

はじめに

皆さんはクリスマスや年末はどのように過ごす予定ですか?1日中布団にくるまって寝るもよし、外に出てスキー、温泉、雪景色を楽しむもよし。それでも暇だ!っていう人にはこれ!!ツリーランゲーム!turi.png

内容

これはクリスマスの夜を駆けるクリスマスツリーです。プレイヤーのクリスマスツリーは雪だるまやプレゼント、靴下の障害物をジャンプして避けてハイスコアを稼ぐ、そんな感じです。

html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ツリーランゲーム</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>ツリーランゲーム</h1>
  <canvas id="game" width="600" height="300"></canvas>
  <script src="main.js"></script>
</body>
</html>

css

body {
  background-color: black;
  color: white;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
}

javascript

const cv = document.getElementById('game');
const ctx = cv.getContext('2d');

let playerY = 150;// ツリー(プレイヤー)の位置
let velocityY = 0;
let jumpCount = 0;//ジャンプ回数のカウント
const maxjumps = 2;//ジャンプ回数上限
let canPress = true;

//回転
let rotation = 0;
let rotating = false;

let gravity = 0.7;
let obstacles = [];
let score = 0;
let gameOver = false;

//ツリー
function drawPlayer() {
  ctx.save();
  ctx.translate(60, playerY + 20);
  if (rotating) ctx.rotate(rotation);

  ctx.fillStyle = "green";

  ctx.fillRect(-2, 10, 4, 10); // 幹

  // 下・中・上の三角
  [[-10, 10, 10, 10, 0, -10],
   [-8, 0, 8, 0, 0, -15],
   [-6, -10, 6, -10, 0, -22]].forEach(p => {
    ctx.beginPath();
    ctx.moveTo(p[0], p[1]);
    ctx.lineTo(p[2], p[3]);
    ctx.lineTo(p[4], p[5]);
    ctx.closePath();
    ctx.fill();
  });

  // 星
  ctx.fillStyle = "gold";
  ctx.beginPath();
  ctx.arc(0, -25, 3, 0, Math.PI * 2);
  ctx.fill();

  ctx.restore();
}

function drawObstacles() {
  obstacles.forEach(o => {
    if (o.type === "snowman") {//雪だるま
      ctx.fillStyle = "white";
      ctx.beginPath();
      ctx.arc(o.x+10, o.y+30, 10, 0, Math.PI*2);
      ctx.fill();
      ctx.beginPath();
      ctx.arc(o.x+10, o.y+15, 7, 0, Math.PI*2);
      ctx.fill();
      ctx.fillStyle = "black";
      ctx.beginPath();
      ctx.arc(o.x+7, o.y+13, 1.5, 0, Math.PI*2);
      ctx.arc(o.x+13, o.y+13, 1.5, 0, Math.PI*2);
      ctx.fill();
    }
        else if (o.type === "gift"){//クリスマスプレゼント箱
        ctx.fillStyle = "red";
        ctx.fillRect(o.x, o.y, o.w, o.h);
        ctx.fillStyle = "yellow";
        ctx.fillRect(o.x+8, o.y, 4, o.h);
        ctx.fillRect(o.x, o.y+18, o.w, 4);
        }
            else if (o.type === "sock") {//靴下
            ctx.fillStyle = "red";
            ctx.beginPath();
            ctx.moveTo(o.x, o.y);
            ctx.lineTo(o.x + 10, o.y);
            ctx.lineTo(o.x + 10, o.y - 20);
            ctx.lineTo(o.x + 5, o.y - 20);
            ctx.lineTo(o.x, o.y - 20);
            ctx.closePath();
            ctx.fill();
            ctx.fillStyle = "white";
            ctx.fillRect(o.x, o.y - 25, 10, 5);
            }
    });
}

function restartGame() {
  playerY = 150;
  velocityY = 0;
  jumpCount = 0;
  rotation = 0;
  rotating = false;
  obstacles = [];
  score = 0;
  gameOver = false;
  update();
}

document.addEventListener('keydown', e => {
  if (e.code === 'Space' && canPress) {
    canPress = false;
    if (gameOver) {
      restartGame();
    } else if (jumpCount < maxjumps) {
      velocityY = -12;
      jumpCount++;
      if (jumpCount === 2) {
        rotating = true;
        rotation = 0;
      }
    }
  }
});

document.addEventListener('keyup', e => {
  if (e.code === 'Space') canPress = true;
});

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

  //プレイヤー更新
  velocityY += gravity;
  playerY += velocityY;
  if (playerY >= 150) {
    playerY = 150;
    velocityY = 0;
    jumpCount = 0;
    rotating = false;
    rotation = 0;
  }

  //2段ジャンプ時の回転の処理
  if (rotating) {
    rotation += 0.3;
    if (rotation >= Math.PI * 2) {
      rotation = 0;
      rotating = false;
    }
  }

  drawPlayer();

  //障害物生成
  if (Math.random() < 0.017) {//障害物の量
    const types = ["snowman", "gift", "sock"];
    const choice = types[Math.floor(Math.random() * types.length)];
    obstacles.push({x:600, y:150, type:choice, w:20, h:40});
  }

  //障害物の更新
  obstacles.forEach(o => o.x -= 5);
  obstacles = obstacles.filter(o => o.x > -20);
  drawObstacles();

  //当たり判定
  obstacles.forEach(o => {
    if (50 < o.x+o.w && 70 > o.x && playerY < o.y+o.h && playerY+40 > o.y ) {
      gameOver = true;
    }
  });

  //スコア
  score++;
  ctx.fillStyle = "white";
  ctx.fillText("Score: " + score, 450, 20 );

  //ゲームオーバー時の表示
  if (gameOver) {
    ctx.fillStyle = "white";
    ctx.font = "20px sans-serif";
    ctx.fillText("おおっと残念、ゲームオーバー!スコア: " + score, 100, 80 );
    ctx.fillText("スペースキーでリスタート", 170, 110);
    return;
  }

  requestAnimationFrame(update);
}

update();

課題

・スペース長押しではジャンプしない
・2回目のジャンプで画面からクリスマスツリーが半分消える
・障害物が重なることがある
・障害物がランダム生成なため、どうしても詰むステージが出てくる

追加したかったもの

・ジャンプ時の効果音
・背景に星々や雲、月、サンタクロースなどをいれたかった

おわりに

今回は時間がかなり迫った状態で作ったのでMicrosoft Copilot様に一部教えていただいたり、整えてもらったりしました。課題はまだ多くありますが、気軽にあそんでみてください。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?