ゲームクリアーを作る(p5.js)

p5.js

今回は敵を全滅させたらゲームクリアーになる処理を作ります。
ついでにゲームオーバー画面も作ります。

function draw() {
  background(220);

  showandmove();
  
  if(areAllEnemiesDefeated(Enemy)){
    background(0);
    text("GAME CREAR!", 330, 200);
    noLoop(); // drawのループを止める
  }
  
  if(!player.isAlive){
    background(0);
    text("GAME OVER!", 330, 200);
    noLoop(); // drawのループを止める
  }
  
  time_limit();
  // スコア表示
  fill(0);
  textSize(24);
  text("Score: " + score, 10, 30);
}

// 指定クラスの敵が全滅したか確認する関数
function areAllEnemiesDefeated(enemyClass) {
  for (let enemy of enemies) {
    if (enemy instanceof enemyClass) {
      return false;  // 指定クラスの敵が残っている場合は全滅していない
    }
  }
  return true;  // 指定クラスの敵が全ていなくなった場合に true を返す
}

areAllEnemiesDefeatedメソッドに主な処理が書いてあります。
if (enemy instanceof enemyClass) で引数enemyClassのインスタンスかどうか判断しています。
for文含めたらenemiesインスタンスを全部調べて引数enemyClassのクラスであるか調べるといういみです。
このメソッドをif(areAllEnemiesDefeated(Enemy))で使うとEnemyクラスのインスタンスがあるか調べるという意味です。
これでゲームクリアーの画面を出すことができます。
ゲームオーバーはplayer.isAliveがfalseだったらゲームオーバー画面が出てくるという風になっています。
次はコードsketch.js全体をお見せします。
sprite.jsは特に変わりないです。

let player; // Mineクラスのインスタンスを保持する変数

// プレイヤーの座標
let gridSize = 40;

let bullets = [];
let enemy_bullets = [];
let enemies = [];
let rows = 5;
let cols = 10;
let enemyWidth = 40;
let enemyHeight = 20;
let spacing = 10;
let enemySpeed = 0.5;
let direction = 1;
let score = 0;

let timeLimit = 60000; // 60秒(ミリ秒)
let startTime;

function setup() {
  createCanvas(800, 400);

  // Mineクラスのインスタンスを1回だけ生成
  player = new Mine(width / 2, height - 40, gridSize);

  player.isAlive = true;
  
  startTime = millis(); // ゲーム開始時の時間を記録
  
  // 敵を初期化
  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      let x = col * (enemyWidth + spacing) + 50;
      let y = row * (enemyHeight + spacing) + 50;
      enemies.push(new Enemy(x, y, enemyWidth, enemyHeight, enemySpeed));
    }
  }
}

function draw() {
  background(220);

  showandmove();
  
  if(areAllEnemiesDefeated(Enemy)){
    background(0);
    text("GAME CREAR!", 330, 200);
    noLoop(); // drawのループを止める
  }
  
  if(!player.isAlive){
    background(0);
    text("GAME OVER!", 330, 200);
    noLoop(); // drawのループを止める
  }
  
  time_limit();
  // スコア表示
  fill(0);
  textSize(24);
  text("Score: " + score, 10, 30);
}

function showandmove(){
  let shouldReverse = false;

  // 弾の表示と移動
  for (let i = bullets.length - 1; i >= 0; i--) {
    bullets[i].display();
    bullets[i].move();
    if (!bullets[i].isVisible) {
      bullets.splice(i, 1);
    }
  }
  
  // 敵の弾の表示と移動
  for (let i = enemy_bullets.length - 1; i >= 0; i--) {
    enemy_bullets[i].display();
    enemy_bullets[i].move();
    if (!enemy_bullets[i].isVisible) {
      enemy_bullets.splice(i, 1);
    }
  }

  // プレイヤーキャラクターを描画
  if (player.isAlive) {
    player.show();
  }

  for (let j = enemy_bullets.length - 1; j >= 0; j--) {
    if (hitTest(enemy_bullets[j], player)) {
      console.log('Player hit by enemy bullet');
      // 当たったら両方とも削除
      enemy_bullets.splice(j, 1);
      player.isAlive = false;
      break; // 敵が消えたのでループから抜ける
    }
  }
  
  // 敵の表示と移動
  for (let i = enemies.length - 1; i >= 0; i--) {
    enemies[i].show();
    enemies[i].move(direction);
    enemies[i].tryShoot();

    if (enemies[i].x > width - enemies[i].w || enemies[i].x < 0) {
      shouldReverse = true;
    }

    // 弾と敵の当たり判定
    for (let j = bullets.length - 1; j >= 0; j--) {
      if (hitTest(bullets[j], enemies[i])) {
        bullets.splice(j, 1);
        enemies.splice(i, 1);
        score += 10;
        break;
      }
    }
  }

  if (shouldReverse) {
    direction *= -1;
    for (let i = 0; i < enemies.length; i++) {
      enemies[i].shiftDown();
    }
  }
}

// 弾と敵の当たり判定
function hitTest(bullet, enemy) {
  return (
    bullet.x > enemy.x &&
    bullet.x < enemy.x + enemy.w &&
    bullet.y > enemy.y &&
    bullet.y < enemy.y + enemy.h
  );
}

function time_limit(){
  let elapsedTime = millis() - startTime; // 経過時間を計算
  let remainingTime = timeLimit - elapsedTime; // 残り時間を計算
  
  if (remainingTime > 0) {
    // ゲームのロジックをここに記述
    textSize(32);
    fill(0);
    text("残り時間: " + floor(remainingTime / 1000), 10, 70); // 残り時間を秒で表示
  } else {
    // 時間切れの処理
    textSize(32);
    fill(255, 0, 0);
    text("時間切れ!", 10, 70);
    noLoop(); // drawのループを止める
  }
}

// 指定クラスの敵が全滅したか確認する関数
function areAllEnemiesDefeated(enemyClass) {
  for (let enemy of enemies) {
    if (enemy instanceof enemyClass) {
      return false;  // 指定クラスの敵が残っている場合は全滅していない
    }
  }
  return true;  // 指定クラスの敵が全ていなくなった場合に true を返す
}

// キーボードイベントを処理する関数
function keyPressed() {
  switch (keyCode) {
    case LEFT_ARROW:
      player.move(-gridSize, 0); // 左に移動
      break;
    case RIGHT_ARROW:
      player.move(gridSize, 0); // 右に移動
      break;
    case UP_ARROW:
      player.move(0, -gridSize); // 上に移動
      break;
    case DOWN_ARROW:
      player.move(0, gridSize); // 下に移動
      break;
  }

  if (key == ' ') {
    let bullet = new Bullet(player.x + 20, player.y);
    bullets.push(bullet);
  }
}

それではまた次回。

コメント


タイトルとURLをコピーしました