Skip to content

Instantly share code, notes, and snippets.

@simonw
Created July 31, 2025 18:50
Show Gist options
  • Select an option

  • Save simonw/b7115990525b104a6dd95f7d694ae6c3 to your computer and use it in GitHub Desktop.

Select an option

Save simonw/b7115990525b104a6dd95f7d694ae6c3 to your computer and use it in GitHub Desktop.

USER

Write an HTML and JavaScript page implementing space invaders

ASSISTANT

Space Invaders Game

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:

  1. Modern UI Design:

    • Neon color scheme with gradient backgrounds
    • Animated starry background
    • Responsive layout for different screen sizes
    • Glowing effects and shadows
  2. 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
  3. 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
  4. 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.

USER

Make the enemy bullets a little slower

ASSISTANT

<!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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment