Some product links are affiliate links which means
if you something we'll receive a small commission.
Youtube Link
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./style.css" />
<title>Missile Game</title>
</head>
<body>
<canvas id="gameCanvas" width="500" height="500"></canvas>
<script src="./index.js"></script>
</body>
</html>
css
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #000;
}
canvas {
display: block;
background-color: #000;
}
js
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const playerImg = new Image();
playerImg.src = "./assets/player.png";
const missileImg = new Image();
missileImg.src = "./assets/missile.png";
const player = {
x: canvas.width / 2,
y: canvas.hidden / 2,
radius: 13,
};
const missiles = [];
let startTime = Date.now();
let isGameOver = false;
function drawScore() {
const currentTime = Date.now();
const timeElapsed = Math.floor((currentTime - startTime) / 1000);
ctx.font = "20px Arial";
ctx.fillStyle = "white";
ctx.fillText("Time: " + timeElapsed + "sec", 10, canvas.height - 10);
}
function createMissile() {
const side = Math.floor(Math.random() * 4);
let x, y;
switch (side) {
case 0:
x = Math.random() * canvas.width;
y = 0;
break;
case 1:
x = Math.random() * canvas.width;
y = canvas.height;
break;
case 2:
x = 0;
y = Math.random() * canvas.height;
break;
case 3:
x = canvas.width;
y = Math.random() * canvas.height;
break;
default:
break;
}
const angle = Math.atan2(player.y - y, player.x - x);
const speed = 1;
const missile = {
x,
y,
radius: 5,
color: "red",
velocityX: Math.cos(angle) * speed,
velocityY: Math.sin(angle) * speed,
};
missiles.push(missile);
}
function moveMissile() {
for (let i = 0; i < missiles.length; i++) {
const missile = missiles[i];
missile.x += missile.velocityX;
missile.y += missile.velocityY;
if (missile.x < 0 || missile.x > canvas.width || missile.y < 0 || missile.y > canvas.height) {
missiles.splice(i, 1);
i--;
}
}
}
function checkCollisions() {
for (let i = 0; i < missiles.length; i++) {
const missile = missiles[i];
const distance = Math.sqrt((player.x - missile.x) ** 2 + (player.y - missile.y) ** 2);
if (distance < player.radius + missile.radius) {
isGameOver = true;
break;
}
}
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function update() {
if (!isGameOver) {
clearCanvas();
drawPlayer();
drawMissiles();
drawScore();
moveMissile();
checkCollisions();
requestAnimationFrame(update);
} else {
ctx.font = "50px VT323, sans-serif";
ctx.fillStyle = "white";
ctx.fillText("Game Over", canvas.width / 2 - 60, canvas.height / 2);
}
}
function drawPlayer() {
ctx.drawImage(playerImg, player.x - player.radius, player.y - player.radius, player.radius * 2, player.radius * 2);
}
function drawMissiles() {
for (let i = 0; i < missiles.length; i++) {
const missile = missiles[i];
ctx.drawImage(missileImg, missile.x - missile.radius, missile.y - missile.radius, missile.radius * 2, missile.radius * 2);
}
}
Promise.all([
new Promise((resolve) => {
playerImg.onload = resolve;
}),
new Promise((resolve) => {
missileImg.onload = resolve;
}),
]).then(() => {
setInterval(createMissile, 150);
update();
});
document.addEventListener("mousemove", (e) => {
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
player.x = Math.min(Math.max(mouseX, player.radius), canvas.width - player.radius);
player.y = Math.min(Math.max(mouseY, player.radius), canvas.height - player.radius);
});