const canvas = document.
getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreDisplay = document.getElementById('score');
const startMessage = document.getElementById('start-message');
const gameWidth = canvas.width;
const gameHeight = canvas.height;
// Game State
let gameStarted = false;
let gameOver = false;
let score = 0;
// Bird properties
const bird = {
x: 50,
y: gameHeight / 2 - 15,
width: 30,
height: 30,
gravity: 0.25,
lift: -5,
velocity: 0
};
// Pipe properties
const pipe = {
width: 50,
gap: 120, // Gap between top and bottom pipe
speed: 2
};
let pipes = [];
// Images (Load your own images)
const birdImg = new Image();
birdImg.src = 'https://i.imgur.com/zW7vN0C.png'; // Replace with your bird image
const pipeNorthImg = new Image();
pipeNorthImg.src = 'https://i.imgur.com/dK8hT0M.png'; // Replace with your top pipe
image
const pipeSouthImg = new Image();
pipeSouthImg.src = 'https://i.imgur.com/P1qg4w0.png'; // Replace with your bottom
pipe image
// Wait for images to load before starting the game
let imagesLoadedCount = 0;
const totalImages = 3;
birdImg.onload = () => { imagesLoadedCount++; checkImagesLoaded(); };
pipeNorthImg.onload = () => { imagesLoadedCount++; checkImagesLoaded(); };
pipeSouthImg.onload = () => { imagesLoadedCount++; checkImagesLoaded(); };
function checkImagesLoaded() {
if (imagesLoadedCount === totalImages) {
startMessage.style.display = 'block'; // Show start message once images are
loaded
}
}
// Event Listeners
canvas.addEventListener('click', startGame);
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' && gameStarted && !gameOver) {
bird.velocity = bird.lift;
}
});
function startGame() {
if (!gameStarted) {
gameStarted = true;
gameOver = false;
score = 0;
scoreDisplay.textContent = `Score: ${score}`;
bird.y = gameHeight / 2 - 15;
bird.velocity = 0;
pipes = [];
startMessage.style.display = 'none';
generateInitialPipes();
gameLoop();
} else if (gameOver) {
// Restart logic if game is over
startGame();
}
}
function generateInitialPipes() {
// Generate a few pipes to start
for (let i = 0; i < 3; i++) {
createPipe(gameWidth + i * 150); // Offset initial pipes
}
}
function createPipe(xPos) {
const minHeight = 50;
const maxHeight = gameHeight - pipe.gap - minHeight;
const topPipeHeight = Math.floor(Math.random() * (maxHeight - minHeight + 1)) +
minHeight;
pipes.push({
x: xPos,
y: 0, // Top pipe y-coordinate
height: topPipeHeight,
passed: false // To check if bird passed this pipe for scoring
});
}
function update() {
if (gameOver || !gameStarted) return;
// Bird physics
bird.velocity += bird.gravity;
bird.y += bird.velocity;
// Boundary collision (top and bottom)
if (bird.y + bird.height > gameHeight || bird.y < 0) {
endGame();
return;
}
// Move and draw pipes
for (let i = 0; i < pipes.length; i++) {
let p = pipes[i];
p.x -= pipe.speed;
// Collision detection with pipes
if (
bird.x < p.x + pipe.width &&
bird.x + bird.width > p.x &&
(bird.y < p.y + p.height || bird.y + bird.height > p.y + p.height +
pipe.gap)
) {
endGame();
return;
}
// Check if pipe is off-screen, remove and add new one
if (p.x + pipe.width < 0) {
pipes.shift(); // Remove the first pipe
createPipe(gameWidth); // Add a new pipe at the end
}
// Score
if (p.x + pipe.width < bird.x && !p.passed) {
score++;
scoreDisplay.textContent = `Score: ${score}`;
p.passed = true;
}
}
}
function draw() {
ctx.clearRect(0, 0, gameWidth, gameHeight);
// Draw bird
ctx.drawImage(birdImg, bird.x, bird.y, bird.width, bird.height);
// Draw pipes
for (let i = 0; i < pipes.length; i++) {
let p = pipes[i];
// Top pipe
ctx.drawImage(pipeNorthImg, p.x, p.y, pipe.width, p.height);
// Bottom pipe
ctx.drawImage(pipeSouthImg, p.x, p.y + p.height + pipe.gap, pipe.width,
gameHeight - (p.y + p.height + pipe.gap));
}
}
function endGame() {
gameOver = true;
startMessage.textContent = `Game Over! Score: ${score}. Click to Restart!`;
startMessage.style.display = 'block';
}
function gameLoop() {
update();
draw();
if (!gameOver) {
requestAnimationFrame(gameLoop);
}
}