sapbot

Flappy bird

Mar 4th, 2026
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 9.45 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Flappy Bird Clone</title>
  7.     <style>
  8.         body {
  9.             margin: 0;
  10.             padding: 0;
  11.             background-color: #333;
  12.             display: flex;
  13.             justify-content: center;
  14.             align-items: center;
  15.             height: 100vh;
  16.             font-family: 'Arial', sans-serif;
  17.             overflow: hidden;
  18.         }
  19.  
  20.         #gameContainer {
  21.             position: relative;
  22.             box-shadow: 0 0 20px rgba(0,0,0,0.5);
  23.         }
  24.  
  25.         canvas {
  26.             display: block;
  27.             background-color: #70c5ce; /* Sky blue */
  28.             border: 2px solid #000;
  29.         }
  30.  
  31.         #uiLayer {
  32.             position: absolute;
  33.             top: 0;
  34.             left: 0;
  35.             width: 100%;
  36.             height: 100%;
  37.             pointer-events: none; /* Let clicks pass through to canvas */
  38.             display: flex;
  39.             flex-direction: column;
  40.             justify-content: center;
  41.             align-items: center;
  42.         }
  43.  
  44.         #scoreDisplay {
  45.             position: absolute;
  46.             top: 20px;
  47.             font-size: 40px;
  48.             font-weight: bold;
  49.             color: white;
  50.             text-shadow: 2px 2px 0 #000;
  51.             z-index: 10;
  52.         }
  53.  
  54.         #startMessage {
  55.             background-color: rgba(0, 0, 0, 0.7);
  56.             color: white;
  57.             padding: 20px 40px;
  58.             border-radius: 10px;
  59.             font-size: 24px;
  60.             text-align: center;
  61.             display: none; /* Hidden by default */
  62.         }
  63.        
  64.         #startMessage.visible {
  65.             display: block;
  66.         }
  67.     </style>
  68. </head>
  69. <body>
  70.  
  71.     <div id="gameContainer">
  72.         <canvas id="gameCanvas" width="400" height="600"></canvas>
  73.        
  74.         <div id="uiLayer">
  75.             <div id="scoreDisplay">0</div>
  76.             <div id="startMessage" class="visible">
  77.                 Press SPACE or Click to Start<br>
  78.                 (Don't hit the pipes!)
  79.             </div>
  80.         </div>
  81.     </div>
  82.  
  83.     <script>
  84.         // --- Configuration ---
  85.         const canvas = document.getElementById('gameCanvas');
  86.         const ctx = canvas.getContext('2d');
  87.         const scoreEl = document.getElementById('scoreDisplay');
  88.         const startMsg = document.getElementById('startMessage');
  89.  
  90.         // Game State
  91.         let frames = 0;
  92.         let score = 0;
  93.         let gameState = 'START'; // START, PLAYING, GAMEOVER
  94.  
  95.         // Bird Object
  96.         const bird = {
  97.             x: 50,
  98.             y: 150,
  99.             width: 30,
  100.             height: 30,
  101.             radius: 15,
  102.             velocity: 0,
  103.             gravity: 0.25,
  104.             jumpStrength: 4.6,
  105.             rotation: 0,
  106.            
  107.             draw: function() {
  108.                 ctx.save();
  109.                 ctx.translate(this.x, this.y);
  110.                 // Rotate bird based on velocity
  111.                 this.rotation = Math.min(Math.PI / 4, Math.max(-Math.PI / 4, (this.velocity * 0.1)));
  112.                 ctx.rotate(this.rotation);
  113.                
  114.                 // Body
  115.                 ctx.fillStyle = "#FFD700"; // Gold
  116.                 ctx.fillRect(-this.width/2, -this.height/2, this.width, this.height);
  117.                 ctx.strokeStyle = "#000";
  118.                 ctx.lineWidth = 2;
  119.                 ctx.strokeRect(-this.width/2, -this.height/2, this.width, this.height);
  120.  
  121.                 // Eye
  122.                 ctx.fillStyle = "#FFF";
  123.                 ctx.fillRect(5, -10, 10, 10);
  124.                 ctx.fillStyle = "#000";
  125.                 ctx.fillRect(10, -5, 2, 2);
  126.  
  127.                 // Beak
  128.                 ctx.fillStyle = "#FFA500"; // Orange
  129.                 ctx.fillRect(10, 5, 10, 8);
  130.                
  131.                 ctx.restore();
  132.             },
  133.            
  134.             update: function() {
  135.                 this.velocity += this.gravity;
  136.                 this.y += this.velocity;
  137.  
  138.                 // Floor Collision
  139.                 if (this.y + this.height/2 >= canvas.height) {
  140.                     this.y = canvas.height - this.height/2;
  141.                     gameOver();
  142.                 }
  143.                
  144.                 // Ceiling Collision (optional, prevents flying over pipes)
  145.                 if (this.y - this.height/2 <= 0) {
  146.                    this.y = this.height/2;
  147.                    this.velocity = 0;
  148.                }
  149.            },
  150.            
  151.            flap: function() {
  152.                this.velocity = -this.jumpStrength;
  153.            },
  154.  
  155.            reset: function() {
  156.                this.y = 150;
  157.                this.velocity = 0;
  158.                this.rotation = 0;
  159.            }
  160.        };
  161.  
  162.        // Pipes Array
  163.        const pipes = {
  164.            items: [],
  165.            width: 50,
  166.            gap: 120,
  167.            dx: 2, // Moving speed
  168.            
  169.            draw: function() {
  170.                for (let i = 0; i < this.items.length; i++) {
  171.                    let p = this.items[i];
  172.                    
  173.                    ctx.fillStyle = "#2E8B57"; // SeaGreen
  174.                    ctx.strokeStyle = "#000";
  175.                    ctx.lineWidth = 2;
  176.  
  177.                    // Top Pipe
  178.                    ctx.fillRect(p.x, 0, this.width, p.top);
  179.                    ctx.strokeRect(p.x, 0, this.width, p.top);
  180.                    
  181.                    // Bottom Pipe
  182.                    ctx.fillRect(p.x, canvas.height - p.bottom, this.width, p.bottom);
  183.                    ctx.strokeRect(p.x, canvas.height - p.bottom, this.width, p.bottom);
  184.                }
  185.            },
  186.            
  187.            update: function() {
  188.                // Add new pipe every 120 frames
  189.                if (frames % 120 === 0) {
  190.                    // Calculate random positions
  191.                    // Minimum pipe height is 50px
  192.                    let availableHeight = canvas.height - this.gap - 100;
  193.                    let randomTop = Math.floor(Math.random() * availableHeight) + 50;
  194.                    
  195.                    this.items.push({
  196.                        x: canvas.width,
  197.                        top: randomTop,
  198.                        bottom: canvas.height - (randomTop + this.gap),
  199.                        passed: false
  200.                    });
  201.                }
  202.  
  203.                // Move pipes
  204.                for (let i = 0; i < this.items.length; i++) {
  205.                    let p = this.items[i];
  206.                    p.x -= this.dx;
  207.  
  208.                    // Collision Detection
  209.                    // 1. Horizontal overlap
  210.                    if (bird.x + bird.width/2 > p.x && bird.x - bird.width/2 < p.x + this.width) {
  211.                        // 2. Vertical overlap (hit top pipe OR hit bottom pipe)
  212.                        if ((bird.y - bird.height/2 < p.top) ||
  213.                            (bird.y + bird.height/2 > canvas.height - p.bottom)) {
  214.                            gameOver();
  215.                         }
  216.                     }
  217.  
  218.                     // Score update
  219.                     if (p.x + this.width < bird.x && !p.passed) {
  220.                        score++;
  221.                        scoreEl.innerText = score;
  222.                        p.passed = true;
  223.                    }
  224.  
  225.                    // Remove off-screen pipes
  226.                    if (p.x + this.width < 0) {
  227.                        this.items.shift();
  228.                        i--;
  229.                    }
  230.                }
  231.            },
  232.  
  233.            reset: function() {
  234.                this.items = [];
  235.            }
  236.        };
  237.  
  238.        // --- Game Control Functions ---
  239.  
  240.        function gameOver() {
  241.            gameState = 'GAMEOVER';
  242.            startMsg.innerHTML = "Game Over<br>Score: " + score + "<br>Press SPACE or Click to Restart";
  243.             startMsg.classList.add('visible');
  244.         }
  245.  
  246.         function resetGame() {
  247.             bird.reset();
  248.             pipes.reset();
  249.             score = 0;
  250.             frames = 0;
  251.             scoreEl.innerText = score;
  252.             gameState = 'PLAYING';
  253.             startMsg.classList.remove('visible');
  254.             loop();
  255.         }
  256.  
  257.         function loop() {
  258.             // Clear Canvas
  259.             ctx.clearRect(0, 0, canvas.width, canvas.height);
  260.  
  261.             if (gameState === 'PLAYING') {
  262.                 pipes.update();
  263.                 pipes.draw();
  264.                 bird.update();
  265.                 bird.draw();
  266.                 frames++;
  267.                 requestAnimationFrame(loop);
  268.             }
  269.         }
  270.  
  271.         // --- Input Handling ---
  272.  
  273.         function handleInput(e) {
  274.             // Prevent default behavior for Space to stop page scrolling
  275.             if (e.type === 'keydown' && e.code === 'Space') {
  276.                e.preventDefault();
  277.             }
  278.  
  279.             if (gameState === 'START' || gameState === 'GAMEOVER') {
  280.                 resetGame();
  281.             } else if (gameState === 'PLAYING') {
  282.                 bird.flap();
  283.             }
  284.         }
  285.  
  286.         // Event Listeners
  287.         window.addEventListener('keydown', (e) => {
  288.             if (e.code === 'Space') handleInput(e);
  289.         });
  290.        
  291.         canvas.addEventListener('mousedown', handleInput);
  292.         canvas.addEventListener('touchstart', (e) => {
  293.             e.preventDefault(); // Prevent scrolling
  294.             handleInput(e);
  295.         }, {passive: false});
  296.  
  297.         // Initial Draw
  298.         bird.draw();
  299.  
  300.     </script>
  301. </body>
  302. </html>
  303.  
Advertisement
Add Comment
Please, Sign In to add comment