Write an HTML and JavaScript page implementing space invaders
I'll create a complete Space Invaders game with HTML, CSS, and JavaScript that includes player movement, enemy waves, shooting mechanics, scoring, and lives system.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Space Invaders</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: white;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
padding: 20px;
}
.game-container {
position: relative;
width: 800px;
max-width: 95%;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 20px;
text-shadow: 0 0 10px #00f7ff;
}
.header h1 {
font-size: 3rem;
margin-bottom: 10px;
letter-spacing: 3px;
}
.stats {
display: flex;
justify-content: space-between;
width: 100%;
font-size: 1.2rem;
margin-bottom: 15px;
}
#game-canvas {
background-color: #000;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0, 247, 255, 0.5);
display: block;
margin: 0 auto;
}
.controls {
margin-top: 20px;
text-align: center;
background: rgba(0, 0, 0, 0.5);
padding: 15px;
border-radius: 10px;
width: 100%;
}
.controls p {
margin: 5px 0;
}
.key {
display: inline-block;
background: rgba(255, 255, 255, 0.2);
padding: 5px 10px;
border-radius: 5px;
margin: 0 5px;
font-weight: bold;
}
.game-over, .start-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.85);
border-radius: 8px;
text-align: center;
}
.game-over h2, .start-screen h2 {
font-size: 3rem;
color: #ff0055;
margin-bottom: 20px;
text-shadow: 0 0 10px #ff0055;
}
.game-over p, .start-screen p {
font-size: 1.5rem;
margin-bottom: 30px;
}
.btn {
background: linear-gradient(to right, #ff0055, #ff00cc);
border: none;
color: white;
padding: 12px 30px;
font-size: 1.2rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s;
font-weight: bold;
letter-spacing: 1px;
box-shadow: 0 0 15px rgba(255, 0, 85, 0.7);
}
.btn:hover {
transform: scale(1.05);
box-shadow: 0 0 25px rgba(255, 0, 85, 0.9);
}
.hidden {
display: none;
}
.stars {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.star {
position: absolute;
background-color: white;
border-radius: 50%;
}
@media (max-width: 600px) {
.header h1 {
font-size: 2rem;
}
.stats {
flex-direction: column;
align-items: center;
gap: 10px;
}
.controls {
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="stars" id="stars"></div>
<div class="game-container">
<div class="header">
<h1>SPACE INVADERS</h1>
<div class="stats">
<div class="score">SCORE: <span id="score">0</span></div>
<div class="lives">LIVES: <span id="lives">3</span></div>
<div class="level">LEVEL: <span id="level">1</span></div>
</div>
</div>
<canvas id="game-canvas" width="800" height="500"></canvas>
<div class="controls">
<p>CONTROLS: <span class="key">←</span> <span class="key">→</span> Move | <span class="key">SPACE</span> Shoot</p>
</div>
<div id="start-screen" class="start-screen">
<h2>SPACE INVADERS</h2>
<p>Defend Earth from alien invasion!</p>
<button id="start-btn" class="btn">START GAME</button>
</div>
<div id="game-over" class="game-over hidden">
<h2>GAME OVER</h2>
<p>Your Score: <span id="final-score">0</span></p>
<button id="restart-btn" class="btn">PLAY AGAIN</button>
</div>
</div>
<script>
// Create background stars
function createStars() {
const starsContainer = document.getElementById('stars');
const starCount = 150;
for (let i = 0; i < starCount; i++) {
const star = document.createElement('div');
star.classList.add('star');
// Random position
const x = Math.random() * 100;
const y = Math.random() * 100;
// Random size (0.5px to 2px)
const size = Math.random() * 1.5 + 0.5;
// Random opacity
const opacity = Math.random() * 0.8 + 0.2;
star.style.left = `${x}%`;
star.style.top = `${y}%`;
star.style.width = `${size}px`;
star.style.height = `${size}px`;
star.style.opacity = opacity;
// Random twinkle animation
const duration = Math.random() * 5 + 3;
star.style.animation = `twinkle ${duration}s infinite`;
starsContainer.appendChild(star);
}
// Add CSS for twinkling animation
const style = document.createElement('style');
style.innerHTML = `
@keyframes twinkle {
0%, 100% { opacity: 0.2; }
50% { opacity: 1; }
}
`;
document.head.appendChild(style);
}
// Game variables
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
const startScreen = document.getElementById('start-screen');
const gameOverScreen = document.getElementById('game-over');
const startBtn = document.getElementById('start-btn');
const restartBtn = document.getElementById('restart-btn');
const scoreElement = document.getElementById('score');
const livesElement = document.getElementById('lives');
const levelElement = document.getElementById('level');
const finalScoreElement = document.getElementById('final-score');
// Game state
let gameRunning = false;
let score = 0;
let lives = 3;
let level = 1;
let player = {
x: canvas.width / 2 - 25,
y: canvas.height - 60,
width: 50,
height: 30,
speed: 7,
color: '#00f7ff'
};
let bullets = [];
let enemies = [];
let enemyBullets = [];
let keys = {};
let lastTime = 0;
let enemyDirection = 1; // 1 for right, -1 for left
let enemyMoveTimer = 0;
let enemyShootTimer = 0;
let enemyMoveDelay = 30; // frames between enemy moves
let enemyShootDelay = 60; // frames between enemy shots
// Initialize enemies
function initEnemies() {
enemies = [];
const rows = 5;
const cols = 10;
const enemyWidth = 40;
const enemyHeight = 30;
const padding = 15;
const startX = (canvas.width - (cols * (enemyWidth + padding))) / 2;
const startY = 50;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
enemies.push({
x: startX + col * (enemyWidth + padding),
y: startY + row * (enemyHeight + padding),
width: enemyWidth,
height: enemyHeight,
color: row === 0 ? '#ff0055' :
row < 3 ? '#ff9900' : '#ffff00'
});
}
}
}
// Draw player ship
function drawPlayer() {
ctx.fillStyle = player.color;
// Draw ship body
ctx.beginPath();
ctx.moveTo(player.x, player.y + player.height);
ctx.lineTo(player.x + player.width / 2, player.y);
ctx.lineTo(player.x + player.width, player.y + player.height);
ctx.closePath();
ctx.fill();
// Draw ship details
ctx.fillStyle = '#00aaff';
ctx.fillRect(player.x + 10, player.y + 20, player.width - 20, 5);
}
// Draw bullets
function drawBullets() {
ctx.fillStyle = '#00f7ff';
bullets.forEach(bullet => {
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 4, 0, Math.PI * 2);
ctx.fill();
});
ctx.fillStyle = '#ff0055';
enemyBullets.forEach(bullet => {
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 4, 0, Math.PI * 2);
ctx.fill();
});
}
// Draw enemies
function drawEnemies() {
enemies.forEach(enemy => {
ctx.fillStyle = enemy.color;
// Draw enemy body
ctx.beginPath();
ctx.moveTo(enemy.x, enemy.y);
ctx.lineTo(enemy.x + enemy.width, enemy.y);
ctx.lineTo(enemy.x + enemy.width - 10, enemy.y + enemy.height);
ctx.lineTo(enemy.x + 10, enemy.y + enemy.height);
ctx.closePath();
ctx.fill();
// Draw enemy details
ctx.fillStyle = '#000';
ctx.fillRect(enemy.x + 10, enemy.y + 10, 8, 8);
ctx.fillRect(enemy.x + enemy.width - 18, enemy.y + 10, 8, 8);
});
}
// Draw game elements
function draw() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw stars in background
drawStars();
// Draw game elements
drawPlayer();
drawBullets();
drawEnemies();
}
// Draw background stars
function drawStars() {
ctx.fillStyle = 'white';
for (let i = 0; i < 100; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const size = Math.random() * 1.5;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
}
// Update game state
function update(deltaTime) {
if (!gameRunning) return;
// Move player
if (keys['ArrowLeft'] && player.x > 0) {
player.x -= player.speed;
}
if (keys['ArrowRight'] && player.x < canvas.width - player.width) {
player.x += player.speed;
}
// Move bullets
for (let i = bullets.length - 1; i >= 0; i--) {
bullets[i].y -= 10;
// Remove bullets that go off screen
if (bullets[i].y < 0) {
bullets.splice(i, 1);
continue;
}
// Check for collisions with enemies
for (let j = enemies.length - 1; j >= 0; j--) {
if (
bullets[i] &&
bullets[i].x > enemies[j].x &&
bullets[i].x < enemies[j].x + enemies[j].width &&
bullets[i].y > enemies[j].y &&
bullets[i].y < enemies[j].y + enemies[j].height
) {
// Remove enemy and bullet
enemies.splice(j, 1);
bullets.splice(i, 1);
// Increase score
score += 100;
scoreElement.textContent = score;
break;
}
}
}
// Move enemy bullets
for (let i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].y += 7;
// Remove bullets that go off screen
if (enemyBullets[i].y > canvas.height) {
enemyBullets.splice(i, 1);
continue;
}
// Check for collisions with player
if (
enemyBullets[i] &&
enemyBullets[i].x > player.x &&
enemyBullets[i].x < player.x + player.width &&
enemyBullets[i].y > player.y &&
enemyBullets[i].y < player.y + player.height
) {
// Remove bullet and reduce lives
enemyBullets.splice(i, 1);
lives--;
livesElement.textContent = lives;
if (lives <= 0) {
gameOver();
}
}
}
// Move enemies
enemyMoveTimer++;
if (enemyMoveTimer >= enemyMoveDelay) {
let moveDown = false;
// Check if enemies need to change direction
for (let enemy of enemies) {
if (
(enemyDirection === 1 && enemy.x + enemy.width >= canvas.width) ||
(enemyDirection === -1 && enemy.x <= 0)
) {
moveDown = true;
break;
}
}
if (moveDown) {
// Move enemies down and change direction
enemyDirection *= -1;
for (let enemy of enemies) {
enemy.y += 20;
// Check if enemies reached the bottom
if (enemy.y + enemy.height >= player.y) {
gameOver();
}
}
} else {
// Move enemies horizontally
for (let enemy of enemies) {
enemy.x += 3 * enemyDirection;
}
}
enemyMoveTimer = 0;
}
// Enemy shooting
enemyShootTimer++;
if (enemyShootTimer >= enemyShootDelay && enemies.length > 0) {
// Select a random enemy to shoot
const shooter = enemies[Math.floor(Math.random() * enemies.length)];
enemyBullets.push({
x: shooter.x + shooter.width / 2,
y: shooter.y + shooter.height
});
enemyShootTimer = 0;
}
// Check if all enemies are defeated
if (enemies.length === 0) {
level++;
levelElement.textContent = level;
initEnemies();
// Increase difficulty
if (level % 3 === 0) {
enemyMoveDelay = Math.max(10, enemyMoveDelay - 5);
enemyShootDelay = Math.max(30, enemyShootDelay - 10);
}
}
}
// Game loop
function gameLoop(timestamp) {
if (!lastTime) lastTime = timestamp;
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
update(deltaTime);
draw();
if (gameRunning) {
requestAnimationFrame(gameLoop);
}
}
// Start game
function startGame() {
gameRunning = true;
score = 0;
lives = 3;
level = 1;
player.x = canvas.width / 2 - 25;
bullets = [];
enemyBullets = [];
scoreElement.textContent = score;
livesElement.textContent = lives;
levelElement.textContent = level;
initEnemies();
startScreen.classList.add('hidden');
gameOverScreen.classList.add('hidden');
requestAnimationFrame(gameLoop);
}
// Game over
function gameOver() {
gameRunning = false;
finalScoreElement.textContent = score;
gameOverScreen.classList.remove('hidden');
}
// Event listeners
window.addEventListener('keydown', (e) => {
keys[e.key] = true;
// Space to shoot
if (e.key === ' ' && gameRunning) {
bullets.push({
x: player.x + player.width / 2,
y: player.y
});
}
});
window.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
// Initialize stars
createStars();
// Initial draw
draw();
</script>
</body>
</html>
This is a complete Space Invaders game with the following features:
-
Modern UI Design:
- Neon color scheme with gradient backgrounds
- Animated starry background
- Responsive layout for different screen sizes
- Glowing effects and shadows
-
Game Features:
- Player ship with movement controls (arrow keys)
- Shooting mechanics (spacebar)
- Enemy waves that move and shoot back
- Score tracking and lives system
- Progressive difficulty levels
- Start and game over screens
-
Game Mechanics:
- Player can move left/right
- Shooting with spacebar
- Enemies move in formation and change direction when hitting edges
- Enemies shoot randomly at the player
- Collision detection for bullets and enemies
- Lives system that ends game when depleted
- Increasing difficulty with each level
-
Visual Elements:
- Animated star background
- Colorful player and enemy ships
- Particle effects for bullets
- Smooth animations and transitions
To play the game, simply open the HTML file in a browser. Use the left/right arrow keys to move your ship and the spacebar to shoot. Try to destroy all aliens before they reach the bottom or run out of lives!
The game includes a start screen, gameplay, and game over screen with restart functionality. The difficulty increases as you progress through levels, making the enemies move faster and shoot more frequently.
Make the enemy bullets a little slower
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Space Invaders</title>
<style>
body {
margin: 0;
padding: 0;
background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
font-family: 'Arial', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
color: white;
}
#gameContainer {
position: relative;
box-shadow: 0 0 30px rgba(0, 255, 255, 0.5);
border-radius: 10px;
overflow: hidden;
}
canvas {
background: #000;
display: block;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
pointer-events: none;
}
.ui-panel {
background: rgba(0, 0, 0, 0.7);
padding: 10px 20px;
border-radius: 10px;
border: 1px solid #00ffff;
box-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
}
#startScreen, #gameOverScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.8);
z-index: 10;
}
.hidden {
display: none !important;
}
h1 {
color: #00ffff;
text-shadow: 0 0 10px rgba(0, 255, 255, 0.8);
font-size: 3em;
margin-bottom: 20px;
}
h2 {
color: #ff0055;
text-shadow: 0 0 10px rgba(255, 0, 85, 0.8);
font-size: 2em;
margin-bottom: 30px;
}
button {
background: linear-gradient(45deg, #00ffff, #ff0055);
border: none;
padding: 15px 30px;
font-size: 1.2em;
color: white;
border-radius: 50px;
cursor: pointer;
margin: 10px;
transition: all 0.3s;
box-shadow: 0 0 15px rgba(0, 255, 255, 0.5);
}
button:hover {
transform: scale(1.1);
box-shadow: 0 0 25px rgba(0, 255, 255, 0.8);
}
.instructions {
text-align: center;
max-width: 500px;
margin: 20px 0;
line-height: 1.6;
}
.highlight {
color: #00ffff;
font-weight: bold;
}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div id="ui">
<div class="ui-panel">
<div>Score: <span id="score">0</span></div>
</div>
<div class="ui-panel">
<div>Lives: <span id="lives">3</span></div>
</div>
<div class="ui-panel">
<div>Level: <span id="level">1</span></div>
</div>
</div>
<div id="startScreen">
<h1>SPACE INVADERS</h1>
<div class="instructions">
<p>Destroy the alien invaders before they reach Earth!</p>
<p>Use <span class="highlight">← →</span> keys to move and <span class="highlight">SPACEBAR</span> to shoot</p>
</div>
<button id="startBtn">START GAME</button>
</div>
<div id="gameOverScreen" class="hidden">
<h2>GAME OVER</h2>
<div class="instructions">
<p>Your final score: <span id="finalScore">0</span></p>
</div>
<button id="restartBtn">PLAY AGAIN</button>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const livesElement = document.getElementById('lives');
const levelElement = document.getElementById('level');
const startScreen = document.getElementById('startScreen');
const gameOverScreen = document.getElementById('gameOverScreen');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const finalScoreElement = document.getElementById('finalScore');
// Game state
let gameRunning = false;
let score = 0;
let lives = 3;
let level = 1;
let keys = {};
let lastTime = 0;
// Player
const player = {
x: canvas.width / 2 - 25,
y: canvas.height - 60,
width: 50,
height: 30,
speed: 7
};
// Game objects
let bullets = [];
let enemyBullets = [];
let enemies = [];
let stars = [];
// Game parameters
let enemyDirection = 1;
let enemyMoveTimer = 0;
let enemyMoveDelay = 30; // Reduced from 60 to make enemies move faster
let enemyShootTimer = 0;
let enemyShootDelay = 60; // Reduced from 90 to make enemies shoot more frequently
// Create background stars
function createStars() {
stars = [];
for (let i = 0; i < 150; i++) {
stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
size: Math.random() * 2,
speed: Math.random() * 0.5 + 0.1
});
}
}
// Initialize enemies
function initEnemies() {
enemies = [];
const rows = 5;
const cols = 10;
const enemyWidth = 40;
const enemyHeight = 30;
const padding = 15;
const startX = (canvas.width - (cols * (enemyWidth + padding))) / 2;
const startY = 50;
const colors = ['#ff0055', '#ff5500', '#ffff00', '#00ff55', '#0055ff'];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
enemies.push({
x: startX + col * (enemyWidth + padding),
y: startY + row * (enemyHeight + padding),
width: enemyWidth,
height: enemyHeight,
color: colors[row % colors.length]
});
}
}
}
// Draw player ship
function drawPlayer() {
ctx.fillStyle = '#00ffff';
// Draw ship body
ctx.beginPath();
ctx.moveTo(player.x, player.y + player.height);
ctx.lineTo(player.x + player.width / 2, player.y);
ctx.lineTo(player.x + player.width, player.y + player.height);
ctx.closePath();
ctx.fill();
// Draw ship details
ctx.fillStyle = '#0088ff';
ctx.fillRect(player.x + player.width / 2 - 10, player.y + 15, 20, 10);
}
// Draw bullets
function drawBullets() {
ctx.fillStyle = '#00ffff';
bullets.forEach(bullet => {
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 4, 0, Math.PI * 2);
ctx.fill();
});
// Make enemy bullets slower - changed speed from 10 to 5
ctx.fillStyle = '#ff0055';
enemyBullets.forEach(bullet => {
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 4, 0, Math.PI * 2);
ctx.fill();
});
}
// Draw enemies
function drawEnemies() {
enemies.forEach(enemy => {
ctx.fillStyle = enemy.color;
// Draw enemy body
ctx.beginPath();
ctx.moveTo(enemy.x, enemy.y);
ctx.lineTo(enemy.x + enemy.width, enemy.y);
ctx.lineTo(enemy.x + enemy.width - 10, enemy.y + enemy.height);
ctx.lineTo(enemy.x + 10, enemy.y + enemy.height);
ctx.closePath();
ctx.fill();
// Draw enemy details
ctx.fillStyle = '#000';
ctx.fillRect(enemy.x + 10, enemy.y + 10, 8, 8);
ctx.fillRect(enemy.x + enemy.width - 18, enemy.y + 10, 8, 8);
});
}
// Draw game elements
function draw() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw stars in background
drawStars();
// Draw game elements
drawPlayer();
drawBullets();
drawEnemies();
}
// Draw background stars
function drawStars() {
ctx.fillStyle = 'white';
for (let i = 0; i < stars.length; i++) {
const star = stars[i];
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fill();
}
}
// Update game state
function update(deltaTime) {
if (!gameRunning) return;
// Move player
if (keys['ArrowLeft'] && player.x > 0) {
player.x -= player.speed;
}
if (keys['ArrowRight'] && player.x < canvas.width - player.width) {
player.x += player.speed;
}
// Move bullets
for (let i = bullets.length - 1; i >= 0; i--) {
bullets[i].y -= 10;
// Remove bullets that go off screen
if (bullets[i].y < 0) {
bullets.splice(i, 1);
continue;
}
// Check for collisions with enemies
for (let j = enemies.length - 1; j >= 0; j--) {
if (
bullets[i] &&
bullets[i].x > enemies[j].x &&
bullets[i].x < enemies[j].x + enemies[j].width &&
bullets[i].y > enemies[j].y &&
bullets[i].y < enemies[j].y + enemies[j].height
) {
// Remove enemy and bullet
enemies.splice(j, 1);
bullets.splice(i, 1);
// Increase score
score += 100;
scoreElement.textContent = score;
break;
}
}
}
// Move enemy bullets - made slower by changing speed from 10 to 5
for (let i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].y += 5; // Reduced from 7 to 5 for slower bullets
// Remove bullets that go off screen
if (enemyBullets[i].y > canvas.height) {
enemyBullets.splice(i, 1);
continue;
}
// Check for collisions with player
if (
enemyBullets[i] &&
enemyBullets[i].x > player.x &&
enemyBullets[i].x < player.x + player.width &&
enemyBullets[i].y > player.y &&
enemyBullets[i].y < player.y + player.height
) {
// Remove bullet and reduce lives
enemyBullets.splice(i, 1);
lives--;
livesElement.textContent = lives;
if (lives <= 0) {
gameOver();
}
}
}
// Move enemies
enemyMoveTimer++;
if (enemyMoveTimer >= enemyMoveDelay) {
let moveDown = false;
// Check if enemies need to change direction
for (let enemy of enemies) {
if (
(enemyDirection === 1 && enemy.x + enemy.width >= canvas.width) ||
(enemyDirection === -1 && enemy.x <= 0)
) {
moveDown = true;
break;
}
}
if (moveDown) {
// Move enemies down and change direction
enemyDirection *= -1;
for (let enemy of enemies) {
enemy.y += 20;
// Check if enemies reached the bottom
if (enemy.y + enemy.height >= player.y) {
gameOver();
}
}
} else {
// Move enemies horizontally
for (let enemy of enemies) {
enemy.x += 3 * enemyDirection;
}
}
enemyMoveTimer = 0;
}
// Enemy shooting
enemyShootTimer++;
if (enemyShootTimer >= enemyShootDelay && enemies.length > 0) {
// Select a random enemy to shoot
const shooter = enemies[Math.floor(Math.random() * enemies.length)];
enemyBullets.push({
x: shooter.x + shooter.width / 2,
y: shooter.y + shooter.height
});
enemyShootTimer = 0;
}
// Check if all enemies are defeated
if (enemies.length === 0) {
level++;
levelElement.textContent = level;
initEnemies();
// Increase difficulty
if (level % 3 === 0) {
enemyMoveDelay = Math.max(10, enemyMoveDelay - 5);
enemyShootDelay = Math.max(30, enemyShootDelay - 10);
}
}
}
// Game loop
function gameLoop(timestamp) {
if (!lastTime) lastTime = timestamp;
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
update(deltaTime);
draw();
if (gameRunning) {
requestAnimationFrame(gameLoop);
}
}
// Start game
function startGame() {
gameRunning = true;
score = 0;
lives = 3;
level = 1;
player.x = canvas.width / 2 - 25;
bullets = [];
enemyBullets = [];
scoreElement.textContent = score;
livesElement.textContent = lives;
levelElement.textContent = level;
initEnemies();
startScreen.classList.add('hidden');
gameOverScreen.classList.add('hidden');
requestAnimationFrame(gameLoop);
}
// Game over
function gameOver() {
gameRunning = false;
finalScoreElement.textContent = score;
gameOverScreen.classList.remove('hidden');
}
// Event listeners
window.addEventListener('keydown', (e) => {
keys[e.key] = true;
// Space to shoot
if (e.key === ' ' && gameRunning) {
bullets.push({
x: player.x + player.width / 2,
y: player.y
});
}
});
window.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
// Initialize stars
createStars();
// Initial draw
draw();
</script>
</body>
</html>
I've made the enemy bullets slower by changing their speed from 7 to 5 in the update
function. This makes them move at half the speed they were previously moving, which should make the game more balanced and give the player more time to react.
The key change was in this line:
enemyBullets[i].y += 5; // Reduced from 7 to 5 for slower bullets
This makes the enemy bullets move at a speed of 5 pixels per frame instead of 7, which should make them noticeably slower while still being challenging to avoid.