canvas实现太空侵略者游戏

1,099 阅读4分钟

太空侵略者游戏 - 为你带来刺激的太空冒险!驾驶你的飞船,与敌人战斗,在无尽的太空中收集能量,并使用它来发射强力子弹。在这个充满挑战和乐趣的游戏中,你将面对无尽的敌人和难度逐渐上升的关卡。你需要提高反应速度、灵活性和战略思维,才能在这个宇宙中生存下去!快来加入我们吧,成为太空侵略者的王者!

使用Canvas和JavaScript创建太空侵略者游戏,我给这款游戏定的目标是消灭所有入侵者并保护地球🧐。

游戏运行效果图和体验链接在文章底部 走过路过不要错过 🤏

创建画布并绘制背景

首先用Canvas元素来绘制游戏画面。代码如下

<canvas id="canvas" width="500" height="500"></canvas>

在画布上绘制一个背景。代码如下:

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);

创建玩家

创建一个玩家来控制,发射子弹击败敌人。

class Player {
  constructor() {
    this.width = 50;
    this.height = 50;
    this.x = canvas.width / 2 - this.width / 2;
    this.y = canvas.height - this.height - 10;
    this.speed = 5;
  }

  draw() {
    ctx.fillStyle = "white";
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }
  moveLeft() {
    this.x -= this.speed;
  }
  moveRight() {
    this.x += this.speed;
  }
}
const player = new Player();

创建敌人

我们需要创建一些敌人来消灭。不然就毫无趣味可言了,敌人在这里我用方块代替,因为没有设计对应的精灵图

class Enemy {
  constructor(x, y) {
    this.width = 50;
    this.height = 50;
    this.x = x;
    this.y = y;
    this.speed = 2;
  }

  draw() {
    ctx.fillStyle = "red";
    ctx.fillRect(this.x, this.y, this.width, this.height);
	  ctx.fillStyle = "white";
	  ctx.font = "15px Arial";
	  ctx.fillText("敌人", this.x + 10, this.y + 25);
  }

  moveDown() {
    this.y += this.speed;
  }
}

const enemies = [];
for (let i = 0; i < 5; i++) {
  for (let j = 0; j < 3; j++) {
    const enemy = new Enemy(i * 60 + 10, j * 60 + 10);
    enemies.push(enemy);
  }
}

控制玩家移动

用键盘控制玩家左右移动。如果你够勇敢,你可以存到敌人后方射击子弹,毕竟你才思如泉涌吗,哈哈哈

document.addEventListener("keydown", (event) => {
  if (event.key === "ArrowLeft") {
    player.moveLeft();
  } else if (event.key === "ArrowRight") {
    player.moveRight();
  }
});

敌人移动

让敌人向下移动来增加游戏难度。当然,你也可以让他群魔乱舞,让玩家的子弹找不着北,哈哈哈

function moveEnemies() {
  enemies.forEach((enemy) => {
    enemy.moveDown();
  });
}

setInterval(() => {
  moveEnemies();
}, 1000);

碰撞检测

我们需要检测玩家和敌人之间的碰撞。当然,你可以给自己开挂,敌人碰到玩家,敌人自动原地die😵

function detectCollision() {
  enemies.forEach((enemy, enemyIndex) => {
    if (
      player.x < enemy.x + enemy.width &&
      player.x + player.width > enemy.x &&
      player.y < enemy.y + enemy.height &&
      player.y + player.height > enemy.y
    ) {
      enemies.splice(enemyIndex, 1);
    }
  });
}

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

  player.draw();
  enemies.forEach((enemy) => {
    enemy.draw();
  });

  detectCollision();

  requestAnimationFrame(gameLoop);
}

gameLoop();

结束游戏

当敌人达到屏幕底部时,游戏结束。我可不想让游戏无限

function isGameOver() {
  let gameOver = false;
  enemies.forEach((enemy) => {
    if (enemy.y + enemy.height >= canvas.height) {
      gameOver = true;
    }
  });
  return gameOver;
}

function gameLoop() {
  // ...

  if (isGameOver()) {
    alert("Game Over");
    location.reload();
  } else {
    requestAnimationFrame(gameLoop);
  }
}

添加玩家攻击

添加玩家攻击敌人的功能。释放子弹,攻击满10次,释放buff,攻击力拉满。

class Player {
  //...

  attack() {
    const laser = new Laser(this.x + this.width / 2 - 2.5, this.y - 10);
    lasers.push(laser);
  }
}

class Laser {
  constructor(x, y) {
    this.width = 5;
    this.height = 10;
    this.x = x;
    this.y = y;
    this.speed = 10;
  }

  draw() {
    ctx.fillStyle = "green";
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }

  moveUp() {
    this.y -= this.speed;
  }
}

const lasers = [];

document.addEventListener("keydown", (event) => {
  if (event.code === "Space") {
    player.attack();
  }
});

function moveLasers() {
  lasers.forEach((laser, laserIndex) => {
    laser.moveUp();
    if (laser.y < 0) {
      lasers.splice(laserIndex, 1);
    }
  });
}

function drawLasers() {
  lasers.forEach((laser) => {
    laser.draw();
  });
}

function gameLoop() {
  // ...

  moveLasers();
  drawLasers();

  requestAnimationFrame(gameLoop);
}

检测敌人被攻击

检测敌人是否被攻击,如果敌人被击中,就将敌人从保存敌人的数组中删除,子弹同理。

function detectCollision() {
  enemies.forEach((enemy, enemyIndex) => {
    lasers.forEach((laser, laserIndex) => {
      if (
        laser.x < enemy.x + enemy.width &&
        laser.x + laser.width > enemy.x &&
        laser.y < enemy.y + enemy.height &&
        laser.y + laser.height > enemy.y
      ) {
        enemies.splice(enemyIndex, 1);
        lasers.splice(laserIndex, 1);
      }
    });
  });
}

function gameLoop() {
  // ...

  detectCollision();

  requestAnimationFrame(gameLoop);
}

实现无限量的敌人

使用一个循环来不断地生成新的敌人,实现无限量敌人的效果。每秒钟生成一个新的敌人。调整间隔时间可以控制敌人生成速度

function generateEnemies() {
  const enemy = new Enemy(Math.random() * canvas.width, 0);
  enemies.push(enemy);
}

setInterval(() => {
  generateEnemies();
}, 1000);

完善体验功能

太空侵略者游戏是一款充满挑战和乐趣的太空冒险游戏。玩家需要驾驶自己的飞船与无尽的敌人战斗,在收集能量的同时使用它来发射强力子弹。游戏中需要提高反应速度、灵活性和战略思维,才能在这个宇宙中生存下去。此外,可以通过添加游戏说明、音效、暂停选项等来改善游戏体验。

不过我偷懒了,我并没有完善的很好,可以在“马上掘金”把代码fork过去修改哦

添加开始按钮

添加开始游戏按钮,方便控制游戏的启动

<button id="start-button" style="border-radius: 5px; background-color: red; color: white; font-size: 16px;">开始游戏</button>

添加点击监听时间,点击后开始游戏

const startButton = document.getElementById("start-button");
startButton.addEventListener("click", () => {
  gameLoop();
});

添加结束按钮

添加结束按钮,方便随时结束游戏进程

<button id="end-button" style="border-radius: 5px; background-color: red; color: white; font-size: 16px;">结束游戏</button>

监听结束按钮点击事件,点击后将重新加载页面

const endButton = document.getElementById('end-button');
endButton.addEventListener('click', () => {
    location.reload();
});

积蓄能量

添加能量计数器和能量条。在画布底部显示能量条,玩家每次攻击时,能量计数器将增加一个点。当能量计数器达到10时,玩家的下一次攻击将发射20个子弹,并清空能量计数器。

class Player {
  constructor() {
    // ...
    this.energy = 0;
    this.energyMax = 10;
  }

  drawEnergyBar() {
    ctx.fillStyle = "white";
    ctx.fillRect(10, canvas.height - 20, 100, 10);
    ctx.fillStyle = "blue";
    ctx.fillRect(10, canvas.height - 20, this.energy / this.energyMax * 100, 10);
  }

  attack() {
    if (this.energy >= this.energyMax) {
      for (let i = 0; i < 20; i++) {
        const laser = new Laser(this.x + this.width / 2 - 2.5 - 20 + i * 2, this.y - 10);
        lasers.push(laser);
      }
      this.energy = 0;
    } else {
      const laser = new Laser(this.x + this.width / 2 - 2.5, this.y - 10);
      lasers.push(laser);
      this.energy++;
    }
  }
}

function detectCollision() {
  enemies.forEach((enemy, enemyIndex) => {
    lasers.forEach((laser, laserIndex) => {
      if (//...... ) {
	//......
        player.energy ++
      }
    });
  });
}

最后,在游戏循环中调用 drawEnergyBar 方法来绘制能量条。可以使用以下代码实现:

function gameLoop() {
  // ...

  player.drawEnergyBar();
  moveLasers();
  drawLasers();
  detectCollision();
  requestAnimationFrame(gameLoop);
}

释放所有interval

在游戏结束时清除所有 setInterval 函数,以确保游戏在结束时不再运行。

let intervalIds = [];

intervalIds.push(setInterval(generateEnemies, 1000));
intervalIds.push(setInterval(moveEnemies, 1000));

//gameLoop方法isGameOver满足后添加
//点击结束事件后添加
intervalIds.forEach(id => clearInterval(id));
intervalIds = [];

运行效果和体验链接

太空游戏.gif

体验链接
太空侵略者游戏 - 码上掘金 (juejin.cn)