Untitled

 avatar
unknown
plain_text
9 months ago
8.4 kB
13
Indexable
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Flappy Bird</title>
    <style>
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #333; /* Dark background for visibility */
            font-family: sans-serif;
        }
        canvas {
            border: 2px solid #000;
            background-color: #70c5ce; /* Light blue sky */
            display: block; /* Remove default canvas bottom margin */
        }
        #instructions {
            position: absolute;
            top: 20px;
            color: white;
            padding: 10px;
            background: rgba(0, 0, 0, 0.5);
            border-radius: 5px;
        }
    </style>
</head>
<body>

    <div id="instructions">
        Click or press SPACE to flap!
    </div>
    
    <canvas id="gameCanvas" width="500" height="800"></canvas>

    <script>
        // --- 1. Setup Canvas and Context ---
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        
        // --- 2. Game Constants ---
        const CANVAS_WIDTH = canvas.width;
        const CANVAS_HEIGHT = canvas.height;
        const PIPE_GAP = 200;       // Vertical space between top and bottom pipe
        const PIPE_SPEED = 2;       // How fast pipes move left
        const PIPE_WIDTH = 50;
        const GRAVITY = 0.5;
        const FLAP_VELOCITY = -10;
        const PIPE_SPAWN_RATE = 1500; // Spawn new pipe every 1500ms
        
        // --- 3. Game State Variables ---
        let bird;
        let pipes = [];
        let score = 0;
        let isGameOver = false;
        let lastPipeTime = 0;
        
        // --- 4. Game Objects ---
        
        // Bird object
        class Bird {
            constructor() {
                this.x = CANVAS_WIDTH / 4;
                this.y = CANVAS_HEIGHT / 2;
                this.radius = 20;
                this.velocity = 0;
            }
            
            update() {
                // Apply gravity
                this.velocity += GRAVITY;
                this.y += this.velocity;
                
                // Limit velocity (optional: to prevent rocket-speed crashes)
                if (this.velocity > 15) this.velocity = 15;
            }
            
            draw() {
                ctx.fillStyle = 'yellow';
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fill();
            }
            
            flap() {
                if (!isGameOver) {
                    this.velocity = FLAP_VELOCITY;
                }
            }
        }
        
        // Pipe object
        class Pipe {
            constructor(x) {
                this.x = x;
                this.width = PIPE_WIDTH;
                // Random height for the top pipe
                this.topHeight = Math.floor(Math.random() * (CANVAS_HEIGHT - 300 - PIPE_GAP)) + 100; 
                this.bottomY = this.topHeight + PIPE_GAP;
                this.bottomHeight = CANVAS_HEIGHT - this.bottomY;
                this.passed = false; // Flag for scoring
            }
            
            update() {
                this.x -= PIPE_SPEED;
            }
            
            draw() {
                ctx.fillStyle = 'green';
                // Top pipe
                ctx.fillRect(this.x, 0, this.width, this.topHeight);
                // Bottom pipe
                ctx.fillRect(this.x, this.bottomY, this.width, this.bottomHeight);
            }
        }
        
        // --- 5. Game Functions ---
        
        function spawnPipe() {
            pipes.push(new Pipe(CANVAS_WIDTH));
        }

        function checkCollision() {
            // 1. Ground/Roof collision
            if (bird.y + bird.radius >= CANVAS_HEIGHT || bird.y - bird.radius <= 0) {
                gameOver();
                return;
            }
            
            // 2. Pipe collision
            for (let i = 0; i < pipes.length; i++) {
                const p = pipes[i];
                
                // Check if bird is horizontally aligned with the pipe
                if (bird.x + bird.radius > p.x && bird.x - bird.radius < p.x + p.width) {
                    
                    // Check collision with the top pipe
                    if (bird.y - bird.radius < p.topHeight) {
                        gameOver();
                        return;
                    }
                    
                    // Check collision with the bottom pipe
                    if (bird.y + bird.radius > p.bottomY) {
                        gameOver();
                        return;
                    }
                }
            }
        }
        
        function updateScore() {
            for (let i = 0; i < pipes.length; i++) {
                const p = pipes[i];
                
                // If the bird has passed the pipe's center and hasn't been scored yet
                if (p.x + p.width < bird.x - bird.radius && !p.passed) {
                    score++;
                    p.passed = true;
                }
            }
        }
        
        function drawScore() {
            ctx.fillStyle = 'white';
            ctx.font = '48px Arial';
            ctx.textAlign = 'center';
            ctx.fillText(score, CANVAS_WIDTH / 2, 60);
        }

        function gameOver() {
            isGameOver = true;
            ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
            ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
            
            ctx.fillStyle = 'white';
            ctx.font = '60px Arial';
            ctx.fillText("GAME OVER", CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2 - 40);
            
            ctx.font = '30px Arial';
            ctx.fillText("Click or press SPACE to restart", CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2 + 30);
        }
        
        function resetGame() {
            bird = new Bird();
            pipes = [];
            score = 0;
            isGameOver = false;
            lastPipeTime = 0;
            // Spawn the first pipe immediately to start the game flow
            spawnPipe(); 
            gameLoop(0); // Restart the game loop
        }
        
        // --- 6. The Main Game Loop (Animation) ---
        
        function gameLoop(timestamp) {
            
            // 1. Clear the canvas
            ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
            
            if (!isGameOver) {
                // 2. Update and Draw Pipes
                if (timestamp - lastPipeTime > PIPE_SPAWN_RATE) {
                    spawnPipe();
                    lastPipeTime = timestamp;
                }
                
                // Filter out pipes that have gone off-screen and update the rest
                pipes = pipes.filter(p => p.x + p.width > 0);
                pipes.forEach(p => {
                    p.update();
                    p.draw();
                });
                
                // 3. Update and Draw Bird
                bird.update();
                bird.draw();
                
                // 4. Check State
                checkCollision();
                updateScore();
                
                // 5. Draw Score
                drawScore();
                
                // 6. Request next frame
                requestAnimationFrame(gameLoop);
            } else {
                gameOver();
            }
        }
        
        // --- 7. Event Listeners ---
        
        function handleInput() {
            if (isGameOver) {
                resetGame();
            } else {
                bird.flap();
            }
        }

        // Handle mouse/touch clicks
        canvas.addEventListener('mousedown', handleInput); 
        canvas.addEventListener('touchstart', handleInput);

        // Handle spacebar press
        document.addEventListener('keydown', (e) => {
            if (e.code === 'Space') {
                e.preventDefault(); // Prevent scrolling when space is pressed
                handleInput();
            }
        });

        // --- 8. Start the Game ---
        resetGame(); // Initializes game components and starts the loop
    </script>
</body>
</html>
Editor is loading...
Leave a Comment