Game
Game
DOCTYPE html>
<html>
<head>
<title>Flappy Bird Fixed</title>
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #2c3e50;
font-family: 'Arial', sans-serif;
}
#gameCanvas {
border: 2px solid black;
background: #4EC0CA;
}
.screen {
position: absolute;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 20px;
border-radius: 10px;
text-align: center;
display: none;
}
#startScreen {
display: block;
}
button {
background: #2ecc71;
border: none;
padding: 10px 20px;
margin: 10px;
color: white;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #27ae60;
}
.title {
font-size: 2.5em;
margin: 20px;
color: #FFD700;
text-shadow: 2px 2px #000;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="400" height="600"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const screens = {
start: document.getElementById('startScreen'),
pause: document.getElementById('pauseScreen'),
end: document.getElementById('endScreen')
};
const scoreDisplays = {
final: document.getElementById('finalScore'),
high: document.getElementById('highScore')
};
// Game state
let gameState = 'start';
let bird = {
x: 50,
y: 300,
velocity: 0,
gravity: 0.5,
jump: -8,
size: 24,
wingAngle: 0,
flapSpeed: 0.3,
color: {
body: '#FFD700',
wing: '#FFB90F',
beak: '#FFA500',
eye: '#000000',
highlight: '#FFFFFF'
}
};
// Event listeners
document.addEventListener('keydown', (e) => {
if (gameState === 'playing') {
if (e.code === 'Space') {
bird.velocity = bird.jump;
bird.wingAngle = Math.PI/4;
}
if (e.code === 'KeyP') togglePause();
}
});
function togglePause() {
isPaused = !isPaused;
screens.pause.style.display = isPaused ? 'block' : 'none';
}
function startGame() {
// Reset game state
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
gameState = 'playing';
bird.y = 300;
bird.velocity = 0;
bird.wingAngle = 0;
bird.flapSpeed = 0.3;
pipes = [];
score = 0;
isPaused = false;
// Clear screens
Object.values(screens).forEach(screen => screen.style.display =
'none');
// Initial draw
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
function endGame() {
gameState = 'end';
if (score > highScore) {
highScore = score;
localStorage.setItem('flappyHighScore', highScore);
}
scoreDisplays.final.textContent = score;
scoreDisplays.high.textContent = highScore;
screens.end.style.display = 'block';
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
animationFrameId = null;
}
}
function createPipe() {
const gapPosition = Math.random() * (canvas.height - pipeGap - 100) +
50;
pipes.push({
x: canvas.width,
topHeight: gapPosition,
bottomY: gapPosition + pipeGap,
passed: false
});
}
function drawBird() {
// Shadow
ctx.save();
ctx.fillStyle = 'rgba(0,0,0,0.2)';
ctx.beginPath();
ctx.ellipse(
bird.x + 3,
bird.y + 8,
bird.size * 0.9,
bird.size * 0.6,
0,
0,
Math.PI * 2
);
ctx.fill();
ctx.restore();
// Body
ctx.fillStyle = bird.color.body;
ctx.beginPath();
ctx.ellipse(
bird.x,
bird.y,
bird.size,
bird.size * 0.8,
0,
0,
Math.PI * 2
);
ctx.fill();
// Wing
ctx.fillStyle = bird.color.wing;
ctx.save();
ctx.translate(bird.x, bird.y);
ctx.rotate(bird.wingAngle);
ctx.beginPath();
ctx.ellipse(
-bird.size * 0.6,
0,
bird.size * 0.6,
bird.size * 0.4,
0,
0,
Math.PI * 2
);
ctx.fill();
ctx.restore();
// Beak
ctx.fillStyle = bird.color.beak;
ctx.beginPath();
ctx.moveTo(bird.x + bird.size * 0.8, bird.y);
ctx.lineTo(bird.x + bird.size * 1.4, bird.y);
ctx.lineTo(bird.x + bird.size * 0.8, bird.y + bird.size * 0.3);
ctx.closePath();
ctx.fill();
// Eye
ctx.fillStyle = bird.color.eye;
ctx.beginPath();
ctx.arc(
bird.x - bird.size * 0.4,
bird.y - bird.size * 0.3,
bird.size * 0.2,
0,
Math.PI * 2
);
ctx.fill();
// Eye highlight
ctx.fillStyle = bird.color.highlight;
ctx.beginPath();
ctx.arc(
bird.x - bird.size * 0.45,
bird.y - bird.size * 0.35,
bird.size * 0.05,
0,
Math.PI * 2
);
ctx.fill();
}
function drawPipe(pipe) {
// Main pipe
const pipeGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
pipeGradient.addColorStop(0, pipeColors.shade);
pipeGradient.addColorStop(1, pipeColors.main);
// Top pipe
ctx.fillStyle = pipeGradient;
ctx.fillRect(pipe.x, 0, pipeWidth, pipe.topHeight);
// Bottom pipe
ctx.fillRect(pipe.x, pipe.bottomY, pipeWidth, canvas.height -
pipe.bottomY);
// Rims
ctx.fillStyle = pipeColors.rim;
ctx.fillRect(pipe.x - 5, pipe.topHeight - 15, pipeWidth + 10, 15);
ctx.fillRect(pipe.x - 5, pipe.bottomY, pipeWidth + 10, 15);
}
function update() {
if (gameState !== 'playing' || isPaused) return;
// Animate wings
bird.wingAngle += bird.flapSpeed;
if (bird.wingAngle > Math.PI/2 || bird.wingAngle < -Math.PI/2) {
bird.flapSpeed *= -1;
}
// Physics
bird.velocity += bird.gravity;
bird.y += bird.velocity;
// Create pipes
if (pipes.length === 0 || pipes[pipes.length-1].x < canvas.width -
pipeSpacing) {
createPipe();
}
// Update pipes
for (let i = pipes.length - 1; i >= 0; i--) {
pipes[i].x -= 2;
// Score
if (!pipes[i].passed && pipes[i].x < bird.x) {
score++;
pipes[i].passed = true;
}
// Collisions
if (bird.y + bird.size > canvas.height || bird.y - bird.size < 0) {
endGame();
}
function draw() {
// Clear canvas
ctx.fillStyle = '#4EC0CA';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw pipes
pipes.forEach(drawPipe);
// Draw bird
drawBird();
// Draw UI
ctx.fillStyle = 'black';
ctx.font = '24px Arial';
ctx.fillText(`Score: ${score}`, 10, 30);
ctx.fillText(`High Score: ${highScore}`, 10, 60);
}
function gameLoop() {
update();
draw();
animationFrameId = requestAnimationFrame(gameLoop);
}
</script>
</body>
</html>