用html5写一个flappybird游戏

<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Flappy Bird</title>

<style>

body {

margin: 0;

padding: 0;

display: flex;

justify-content: center;

align-items: center;

min-height: 100vh;

background: linear-gradient(to bottom, #4EC0CA 0%, #87CEEB 100%);

font-family: Arial, sans-serif;

}

#gameContainer {

position: relative;

width: 400px;

height: 600px;

border: 3px solid #333;

overflow: hidden;

background: linear-gradient(to bottom, #4EC0CA 0%, #87CEEB 100%);

}

#canvas {

display: block;

}

#score {

position: absolute;

top: 20px;

left: 50%;

transform: translateX(-50%);

font-size: 48px;

font-weight: bold;

color: white;

text-shadow: 2px 2px 4px rgba(0,0,0,0.5);

z-index: 10;

}

#gameOver {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%, -50%);

text-align: center;

display: none;

z-index: 20;

}

#gameOver h2 {

font-size: 48px;

color: white;

text-shadow: 2px 2px 4px rgba(0,0,0,0.8);

margin-bottom: 20px;

}

#restartBtn {

padding: 15px 30px;

font-size: 24px;

background: #FF6B35;

color: white;

border: none;

border-radius: 5px;

cursor: pointer;

box-shadow: 0 4px 6px rgba(0,0,0,0.3);

}

#restartBtn:hover {

background: #E55A2B;

}

#startScreen {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%, -50%);

text-align: center;

z-index: 30;

}

#startScreen h1 {

font-size: 36px;

color: white;

text-shadow: 2px 2px 4px rgba(0,0,0,0.8);

margin-bottom: 20px;

}

#startBtn {

padding: 15px 30px;

font-size: 24px;

background: #4CAF50;

color: white;

border: none;

border-radius: 5px;

cursor: pointer;

box-shadow: 0 4px 6px rgba(0,0,0,0.3);

}

#startBtn:hover {

background: #45a049;

}

</style>

</head>

<body>

<div id="gameContainer">

<canvas id="canvas" width="400" height="600"></canvas>

<div id="score">0</div>

<div id="startScreen">

<h1>Flappy Bird</h1>

<button id="startBtn">开始游戏</button>

</div>

<div id="gameOver">

<h2>游戏结束</h2>

<p style="color: white; font-size: 24px; text-shadow: 2px 2px 4px rgba(0,0,0,0.8);">得分: <span id="finalScore">0</span></p>

<button id="restartBtn">重新开始</button>

</div>

</div>

<script>

const canvas = document.getElementById('canvas');

const ctx = canvas.getContext('2d');

const scoreElement = document.getElementById('score');

const gameOverElement = document.getElementById('gameOver');

const finalScoreElement = document.getElementById('finalScore');

const startScreen = document.getElementById('startScreen');

const startBtn = document.getElementById('startBtn');

const restartBtn = document.getElementById('restartBtn');

// 游戏状态

let gameStarted = false;

let gameOver = false;

let score = 0;

// 小鸟对象

const bird = {

x: 100,

y: canvas.height / 2,

width: 40,

height: 30,

velocity: 0,

gravity: 0.6,

jumpPower: -12,

color: '#FFD700'

};

// 管道数组

let pipes = [];

const pipeWidth = 80;

const pipeGap = 150;

const pipeSpeed = 3;

let pipeTimer = 0;

// 背景

const background = {

x: 0,

speed: 1

};

// 绘制小鸟

function drawBird() {

ctx.save();

ctx.translate(bird.x + bird.width / 2, bird.y + bird.height / 2);

// 身体

ctx.fillStyle = bird.color;

ctx.beginPath();

ctx.arc(0, 0, bird.width / 2, 0, Math.PI * 2);

ctx.fill();

// 眼睛

ctx.fillStyle = 'white';

ctx.beginPath();

ctx.arc(8, -5, 8, 0, Math.PI * 2);

ctx.fill();

ctx.fillStyle = 'black';

ctx.beginPath();

ctx.arc(10, -5, 4, 0, Math.PI * 2);

ctx.fill();

// 嘴巴

ctx.fillStyle = '#FF6B35';

ctx.beginPath();

ctx.moveTo(15, 0);

ctx.lineTo(25, 3);

ctx.lineTo(15, 6);

ctx.closePath();

ctx.fill();

// 翅膀

ctx.fillStyle = '#FFA500';

ctx.beginPath();

ctx.ellipse(-10, 5, 15, 8, -0.3, 0, Math.PI * 2);

ctx.fill();

ctx.restore();

}

// 绘制管道

function drawPipes() {

pipes.forEach(pipe => {

// 上管道

const gradient1 = ctx.createLinearGradient(pipe.x, 0, pipe.x + pipeWidth, 0);

gradient1.addColorStop(0, '#2E7D32');

gradient1.addColorStop(1, '#4CAF50');

ctx.fillStyle = gradient1;

ctx.fillRect(pipe.x, 0, pipeWidth, pipe.topHeight);

// 下管道

const gradient2 = ctx.createLinearGradient(pipe.x, canvas.height - pipe.bottomHeight, pipe.x + pipeWidth, canvas.height);

gradient2.addColorStop(0, '#2E7D32');

gradient2.addColorStop(1, '#4CAF50');

ctx.fillStyle = gradient2;

ctx.fillRect(pipe.x, canvas.height - pipe.bottomHeight, pipeWidth, pipe.bottomHeight);

// 管道边缘

ctx.fillStyle = '#1B5E20';

ctx.fillRect(pipe.x - 5, pipe.topHeight - 30, pipeWidth + 10, 30);

ctx.fillRect(pipe.x - 5, canvas.height - pipe.bottomHeight, pipeWidth + 10, 30);

});

}

// 绘制背景

function drawBackground() {

// 天空渐变

const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);

gradient.addColorStop(0, '#4EC0CA');

gradient.addColorStop(1, '#87CEEB');

ctx.fillStyle = gradient;

ctx.fillRect(0, 0, canvas.width, canvas.height);

// 云朵

ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';

drawCloud(50, 100);

drawCloud(200, 150);

drawCloud(350, 80);

}

// 绘制云朵

function drawCloud(x, y) {

ctx.beginPath();

ctx.arc(x, y, 25, 0, Math.PI * 2);

ctx.arc(x + 25, y, 35, 0, Math.PI * 2);

ctx.arc(x + 50, y, 25, 0, Math.PI * 2);

ctx.fill();

}

// 创建新管道

function createPipe() {

const minHeight = 100;

const maxHeight = canvas.height - pipeGap - minHeight;

const topHeight = Math.random() * (maxHeight - minHeight) + minHeight;

const bottomHeight = canvas.height - topHeight - pipeGap;

pipes.push({

x: canvas.width,

topHeight: topHeight,

bottomHeight: bottomHeight,

passed: false

});

}

// 更新游戏

function update() {

if (!gameStarted || gameOver) return;

// 更新小鸟

bird.velocity += bird.gravity;

bird.y += bird.velocity;

// 更新管道

pipeTimer++;

if (pipeTimer > 90) {

createPipe();

pipeTimer = 0;

}

pipes.forEach((pipe, index) => {

pipe.x -= pipeSpeed;

// 检查得分

if (!pipe.passed && pipe.x + pipeWidth < bird.x) {

pipe.passed = true;

score++;

scoreElement.textContent = score;

}

// 移除屏幕外的管道

if (pipe.x + pipeWidth < 0) {

pipes.splice(index, 1);

}

});

// 检查碰撞

checkCollision();

// 检查边界

if (bird.y < 0 || bird.y + bird.height > canvas.height) {

endGame();

}

}

// 检查碰撞

function checkCollision() {

pipes.forEach(pipe => {

if (bird.x < pipe.x + pipeWidth &&

bird.x + bird.width > pipe.x &&

(bird.y < pipe.topHeight || bird.y + bird.height > canvas.height - pipe.bottomHeight)) {

endGame();

}

});

}

// 结束游戏

function endGame() {

gameOver = true;

finalScoreElement.textContent = score;

gameOverElement.style.display = 'block';

}

// 绘制游戏

function draw() {

ctx.clearRect(0, 0, canvas.width, canvas.height);

drawBackground();

drawPipes();

drawBird();

}

// 游戏循环

function gameLoop() {

update();

draw();

requestAnimationFrame(gameLoop);

}

// 跳跃

function jump() {

if (!gameStarted) return;

if (gameOver) return;

bird.velocity = bird.jumpPower;

}

// 开始游戏

function startGame() {

gameStarted = true;

gameOver = false;

score = 0;

scoreElement.textContent = score;

bird.y = canvas.height / 2;

bird.velocity = 0;

pipes = [];

pipeTimer = 0;

gameOverElement.style.display = 'none';

startScreen.style.display = 'none';

}

// 重新开始游戏

function restartGame() {

startGame();

}

// 事件监听

canvas.addEventListener('click', jump);

document.addEventListener('keydown', (e) => {

if (e.code === 'Space') {

e.preventDefault();

jump();

}

});

startBtn.addEventListener('click', startGame);

restartBtn.addEventListener('click', restartGame);

// 启动游戏循环

gameLoop();

</script>

</body>

</html>

相关推荐
孩子 你要相信光2 小时前
css之一个元素可以同时应用多个动画效果
前端·css
小刘鸭地下城4 小时前
优雅表格设计:CSS 美化技巧详解
css
小刘鸭地下城5 小时前
网页深色模式完整实现:从响应式设计到系统主题联动
css
恶猫7 小时前
javascript文本长度检测与自动截取,用于标题长度检测
javascript·css·css3·js·自动检测·文本长度
Hilaku8 小时前
我为什么认为 CSS-in-JS 是一个失败的技术?
前端·css·前端框架
Giant1009 小时前
0 基础也能懂的 Flex 布局教程:3 步搞定网页排版
css
Sherry0079 小时前
【译】掌握 Flexbox 的终极指南:从烤肉串到鸡尾酒香肠的布局哲学
css·面试·flexbox
那一抹阳光多灿烂12 小时前
CSS 编码规范
前端·css
degree52012 小时前
CSS :has() 选择器详解:为什么它是“父选择器”?如何实现真正的容器查询?
前端·css·css3