Learn how to create a Flappy Bird clone game using HTML, CSS, and JavaScript. This tutorial provides complete code, from game mechanics to visuals, with a professional and colorful design. Perfect for beginner to intermediate developers looking to enhance their game development skills.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flappy Bird</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="game-container">
<h1>Flappy Bird</h1>
<canvas id="gameCanvas" width="400" height="600"></canvas>
<div class="controls">
<button onclick="startGame()">Start Game</button>
<p id="score">Score: 0</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
style.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #70c5ce;
text-align: center;
}
.game-container {
background: linear-gradient(135deg, #ffb3b3, #ff6666);
border-radius: 20px;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
width: 450px;
}
h1 {
color: white;
font-size: 36px;
margin-bottom: 20px;
}
canvas {
background-color: #70c5ce;
border: 5px solid #fff;
border-radius: 10px;
}
.controls {
margin-top: 20px;
}
button {
background-color: #4caf50;
color: white;
border: none;
padding: 10px 20px;
font-size: 18px;
cursor: pointer;
border-radius: 10px;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #45a049;
}
#score {
font-size: 20px;
margin-top: 10px;
}
script.js
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
let bird, pipes, score, gameInterval, isGameOver;
const GRAVITY = 0.25;
const FLAP_STRENGTH = -4.5;
const SPAWN_RATE = 90; // Frames between pipe spawns
const PIPE_WIDTH = 50;
const PIPE_SPACING = 150; // Space between top and bottom pipes
function startGame() {
bird = {
x: 50,
y: canvas.height / 2,
width: 30,
height: 30,
velocity: 0,
};
pipes = [];
score = 0;
isGameOver = false;
document.getElementById("score").innerText = `Score: ${score}`;
clearInterval(gameInterval);
gameInterval = setInterval(gameLoop, 1000 / 60); // 60 frames per second
}
function gameLoop() {
clearCanvas();
drawBird();
moveBird();
spawnPipes();
movePipes();
checkCollisions();
drawPipes();
updateScore();
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function drawBird() {
ctx.fillStyle = "#FFD700"; // Yellow color for the bird
ctx.fillRect(bird.x, bird.y, bird.width, bird.height);
}
function moveBird() {
bird.velocity += GRAVITY;
bird.y += bird.velocity;
if (bird.y > canvas.height - bird.height) {
endGame();
}
}
function spawnPipes() {
if (frames % SPAWN_RATE === 0) {
let topPipeHeight = Math.floor(Math.random() * (canvas.height / 2));
let bottomPipeHeight = canvas.height - topPipeHeight - PIPE_SPACING;
pipes.push({ x: canvas.width, topHeight: topPipeHeight, bottomHeight: bottomPipeHeight });
}
}
function movePipes() {
for (let i = pipes.length - 1; i >= 0; i--) {
pipes[i].x -= 2; // Pipe speed
if (pipes[i].x + PIPE_WIDTH < 0) {
pipes.splice(i, 1);
}
}
}
function drawPipes() {
ctx.fillStyle = "#228B22"; // Forest green for pipes
for (let i = 0; i < pipes.length; i++) {
let pipe = pipes[i];
// Draw top pipe
ctx.fillRect(pipe.x, 0, PIPE_WIDTH, pipe.topHeight);
// Draw bottom pipe
ctx.fillRect(pipe.x, canvas.height - pipe.bottomHeight, PIPE_WIDTH, pipe.bottomHeight);
}
}
function checkCollisions() {
// Check for collision with pipes
for (let i = 0; i < pipes.length; i++) {
let pipe = pipes[i];
if (
bird.x + bird.width > pipe.x &&
bird.x < pipe.x + PIPE_WIDTH &&
(bird.y < pipe.topHeight || bird.y + bird.height > canvas.height - pipe.bottomHeight)
) {
endGame();
}
}
// Check for collision with floor
if (bird.y + bird.height > canvas.height) {
endGame();
}
}
function updateScore() {
// Increase score if bird passes a pipe
for (let i = 0; i < pipes.length; i++) {
if (pipes[i].x + PIPE_WIDTH < bird.x && !pipes[i].scored) {
pipes[i].scored = true;
score++;
document.getElementById("score").innerText = `Score: ${score}`;
}
}
}
function endGame() {
clearInterval(gameInterval);
alert(`Game Over! Your final score is: ${score}`);
}
document.addEventListener("keydown", (event) => {
if (event.key === " " && !isGameOver) {
bird.velocity = FLAP_STRENGTH;
}
});
let frames = 0;
startGame();

