<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>像素鸟游戏复刻版</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
overflow: hidden;
padding: 20px;
}
.game-container {
position: relative;
width: 800px;
max-width: 95%;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.game-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
background: rgba(0, 0, 0, 0.7);
padding: 15px 25px;
border-radius: 15px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
}
.game-title {
color: white;
font-size: 2.2rem;
letter-spacing: 2px;
text-shadow: 0 0 10px #ff9900;
}
.game-stats {
display: flex;
gap: 25px;
}
.stat-box {
background: rgba(255, 255, 255, 0.9);
padding: 10px 20px;
border-radius: 10px;
text-align: center;
min-width: 120px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.stat-label {
font-weight: bold;
color: #333;
font-size: 1rem;
}
.stat-value {
font-weight: bold;
color: #ff6600;
font-size: 1.8rem;
}
.game-canvas-container {
position: relative;
width: 100%;
background: #70c5ce;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5);
}
canvas {
display: block;
}
.theme-controls {
display: flex;
justify-content: center;
gap: 30px;
margin-top: 10px;
}
.btn {
background: linear-gradient(45deg, #ff8a00, #ff2070);
color: white;
border: none;
padding: 12px 25px;
font-size: 1.1rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: bold;
letter-spacing: 1px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
}
.btn:active {
transform: translateY(1px);
}
#themeToggleBtn {
background: linear-gradient(45deg, #4776E6, #8E54E9);
}
#skinShopBtn {
background: linear-gradient(45deg, #00c9ff, #92fe9d);
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
visibility: hidden;
transition: all 0.4s;
z-index: 100;
}
.modal.active {
opacity: 1;
visibility: visible;
}
.modal-content {
background: linear-gradient(135deg, #2c3e50, #1a1a2e);
width: 90%;
max-width: 800px;
padding: 30px;
border-radius: 20px;
position: relative;
transform: translateY(-20px);
transition: transform 0.4s;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.7);
max-height: 90vh;
overflow-y: auto;
}
.modal.active .modal-content {
transform: translateY(0);
}
.close-modal {
position: absolute;
top: 20px;
right: 25px;
font-size: 2rem;
color: white;
cursor: pointer;
transition: transform 0.3s;
}
.close-modal:hover {
transform: rotate(90deg);
color: #ff5252;
}
.modal-title {
color: white;
text-align: center;
margin-bottom: 25px;
font-size: 2.2rem;
text-shadow: 0 0 10px #00b4d8;
}
.skin-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.skin-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 15px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
border: 2px solid transparent;
}
.skin-card:hover {
background: rgba(255, 255, 255, 0.15);
transform: translateY(-5px);
}
.skin-card.selected {
border-color: #00e5ff;
box-shadow: 0 0 15px rgba(0, 229, 255, 0.7);
}
.skin-card.locked {
filter: grayscale(80%);
opacity: 0.7;
cursor: not-allowed;
}
.skin-preview {
width: 100%;
height: 120px;
border-radius: 8px;
margin-bottom: 10px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.skin-name {
color: white;
font-weight: bold;
margin: 8px 0;
}
.skin-price {
color: #ffcc00;
font-size: 1.1rem;
font-weight: bold;
}
#buySkinBtn {
display: block;
margin: 20px auto 0;
padding: 14px 45px;
font-size: 1.2rem;
}
.notification {
position: fixed;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 15px 25px;
border-radius: 10px;
transform: translateX(200%);
transition: transform 0.5s;
z-index: 200;
}
.notification.show {
transform: translateX(0);
}
@media (max-width: 600px) {
.game-header {
flex-direction: column;
gap: 15px;
}
.game-title {
font-size: 1.8rem;
}
.skin-grid {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.theme-controls {
flex-direction: column;
gap: 15px;
}
.btn {
width: 100%;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="game-header">
<div class="game-title">像素鸟复刻版</div>
<div class="game-stats">
<div class="stat-box">
<div class="stat-label">分数</div>
<div id="score" class="stat-value">0</div>
</div>
<div class="stat-box">
<div class="stat-label">金币</div>
<div id="coins" class="stat-value">50</div>
</div>
</div>
</div>
<div class="game-canvas-container">
<canvas id="gameCanvas" width="800" height="500"></canvas>
</div>
<div class="theme-controls">
<button id="themeToggleBtn" class="btn">切换昼夜</button>
<button id="skinShopBtn" class="btn">皮肤商店</button>
<button id="startBtn" class="btn">开始游戏</button>
</div>
</div>
<!-- 皮肤商店弹窗 -->
<div id="skinShop" class="modal">
<div class="modal-content">
<span class="close-modal">×</span>
<h2 class="modal-title">皮肤商店</h2>
<div class="skin-grid" id="skinContainer">
<!-- 皮肤将通过JavaScript动态添加 -->
</div>
<button id="buySkinBtn" class="btn">购买并应用</button>
</div>
</div>
<div id="notification" class="notification">
<p>购买成功!已应用新皮肤</p>
</div>
<script>
// 游戏常量
const GRAVITY = 0.5;
const JUMP_FORCE = -10;
const PIPE_WIDTH = 70;
const PIPE_GAP = 180;
const PIPE_SPACING = 250;
const GROUND_HEIGHT = 100;
const BIRD_WIDTH = 40;
const BIRD_HEIGHT = 30;
// DOM 元素
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const coinsElement = document.getElementById('coins');
const themeToggleBtn = document.getElementById('themeToggleBtn');
const skinShopBtn = document.getElementById('skinShopBtn');
const startBtn = document.getElementById('startBtn');
const skinShop = document.getElementById('skinShop');
const closeModal = document.querySelector('.close-modal');
const skinContainer = document.getElementById('skinContainer');
const buySkinBtn = document.getElementById('buySkinBtn');
const notification = document.getElementById('notification');
// 游戏状态
let gameState = 'start'; // start, playing, gameover
let score = 0;
let coins = 50;
let dayMode = true;
let selectedSkin = 'green';
// 皮肤数据
const skins = [
{ id: 'green', name: '森林管道', price: 0, unlocked: true },
{ id: 'winter', name: '冬季管道', price: 20, unlocked: false },
{ id: 'desert', name: '沙漠管道', price: 30, unlocked: false },
{ id: 'candy', name: '糖果管道', price: 40, unlocked: false },
{ id: 'gold', name: '黄金管道', price: 50, unlocked: false },
{ id: 'diamond', name: '钻石管道', price: 100, unlocked: false }
];
// 鸟对象
const bird = {
x: 100,
y: canvas.height / 2 - 15,
width: BIRD_WIDTH,
height: BIRD_HEIGHT,
velocity: 0,
draw: function() {
ctx.save();
// 绘制鸟的身体
ctx.fillStyle = dayMode ? '#FFD700' : '#FFA500';
ctx.beginPath();
ctx.arc(this.x + 15, this.y + 15, 15, 0, Math.PI * 2);
ctx.fill();
// 绘制鸟的眼睛
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(this.x + 20, this.y + 12, 3, 0, Math.PI * 2);
ctx.fill();
// 绘制鸟的喙
ctx.fillStyle = '#FF8C00';
ctx.beginPath();
ctx.moveTo(this.x + 25, this.y + 15);
ctx.lineTo(this.x + 35, this.y + 15);
ctx.lineTo(this.x + 25, this.y + 20);
ctx.fill();
// 绘制鸟的翅膀
ctx.fillStyle = dayMode ? '#FF6347' : '#CD5C5C';
ctx.beginPath();
ctx.moveTo(this.x + 10, this.y + 15);
ctx.quadraticCurveTo(this.x + 5, this.y + 25, this.x + 10, this.y + 25);
ctx.quadraticCurveTo(this.x + 15, this.y + 20, this.x + 10, this.y + 15);
ctx.fill();
ctx.restore();
},
update: function() {
// 应用重力
this.velocity += GRAVITY;
this.y += this.velocity;
// 地面碰撞检测
if (this.y + this.height > canvas.height - GROUND_HEIGHT) {
this.y = canvas.height - GROUND_HEIGHT - this.height;
if (gameState === 'playing') {
gameOver();
}
}
// 天花板碰撞检测
if (this.y < 0) {
this.y = 0;
this.velocity = 0;
}
},
jump: function() {
if (gameState === 'playing') {
this.velocity = JUMP_FORCE;
} else if (gameState === 'start') {
startGame();
}
},
reset: function() {
this.y = canvas.height / 2 - 15;
this.velocity = 0;
}
};
// 管道数组
const pipes = [];
// 管道对象
class Pipe {
constructor() {
this.x = canvas.width;
this.width = PIPE_WIDTH;
this.gapStart = Math.random() * (canvas.height - GROUND_HEIGHT - PIPE_GAP - 50) + 25;
this.gapEnd = this.gapStart + PIPE_GAP;
this.passed = false;
}
draw() {
// 上管道
ctx.fillStyle = this.getPipeColor();
ctx.fillRect(this.x, 0, this.width, this.gapStart);
// 下管道
ctx.fillRect(this.x, this.gapEnd, this.width, canvas.height - this.gapEnd);
// 管道帽
ctx.fillStyle = this.getPipeCapColor();
ctx.fillRect(this.x - 5, this.gapStart - 20, this.width + 10, 20);
ctx.fillRect(this.x - 5, this.gapEnd, this.width + 10, 20);
}
update() {
this.x -= 3;
// 检查鸟是否通过管道
if (!this.passed && this.x + this.width < bird.x) {
score++;
scoreElement.textContent = score;
this.passed = true;
// 获得金币
coins++;
coinsElement.textContent = coins;
}
// 碰撞检测
if (detectCollision(bird, this)) {
gameOver();
}
}
isOffScreen() {
return this.x + this.width < 0;
}
getPipeColor() {
switch(selectedSkin) {
case 'winter': return '#A4DEF9';
case 'desert': return '#DEB887';
case 'candy': return '#FF9AA2';
case 'gold': return '#FFD700';
case 'diamond': return '#B9F2FF';
default: return '#4CAF50'; // green
}
}
getPipeCapColor() {
switch(selectedSkin) {
case 'winter': return '#70d6ff';
case 'desert': return '#E1C16E';
case 'candy': return '#FFB7C5';
case 'gold': return '#FFA500';
case 'diamond': return '#66FFFF';
default: return '#2E8B57'; // green
}
}
}
// 精确碰撞检测函数
function detectCollision(bird, pipe) {
// 鸟的边界
const birdLeft = bird.x;
const birdRight = bird.x + bird.width;
const birdTop = bird.y;
const birdBottom = bird.y + bird.height;
// 下管道的边界
const bottomPipeTop = pipe.gapEnd;
// 检测与上管道的碰撞
if (birdRight > pipe.x &&
birdLeft < pipe.x + pipe.width &&
birdTop < pipe.gapStart) {
return true;
}
// 检测与下管道的碰撞
if (birdRight > pipe.x &&
birdLeft < pipe.x + pipe.width &&
birdBottom > bottomPipeTop) {
return true;
}
return false;
}
// 游戏函数
function startGame() {
gameState = 'playing';
score = 0;
scoreElement.textContent = score;
pipes.length = 0;
bird.reset();
}
function gameOver() {
gameState = 'gameover';
// 添加新的金币
coins += Math.floor(score / 5);
coinsElement.textContent = coins;
// 短暂暂停后回到开始状态
setTimeout(() => {
gameState = 'start';
}, 2000);
}
// 添加新管道
function addPipe() {
if (gameState === 'playing' &&
(pipes.length === 0 ||
canvas.width - pipes[pipes.length - 1].x > PIPE_SPACING)) {
pipes.push(new Pipe());
}
}
// 游戏循环
function gameLoop() {
// 绘制背景
if (dayMode) {
ctx.fillStyle = '#87CEEB';
} else {
ctx.fillStyle = '#1a1a2e';
}
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制云朵(只在白天模式)
if (dayMode) {
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
for(let i = 0; i < 5; i++) {
const x = (Date.now() / 40 + i * 100) % (canvas.width + 200) - 100;
ctx.beginPath();
ctx.arc(x, 70, 25, 0, Math.PI * 2);
ctx.arc(x + 20, 65, 20, 0, Math.PI * 2);
ctx.arc(x + 40, 70, 25, 0, Math.PI * 2);
ctx.fill();
}
}
// 绘制星星(只在夜晚模式)
if (!dayMode) {
ctx.fillStyle = 'white';
for(let i = 0; i < 50; i++) {
const x = i * 20 % canvas.width;
const y = (i * 7) % 200;
const size = Math.sin(Date.now() / 1000 + i) * 0.8 + 1.2;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
}
// 绘制地面
ctx.fillStyle = dayMode ? '#8B4513' : '#654321';
ctx.fillRect(0, canvas.height - GROUND_HEIGHT, canvas.width, GROUND_HEIGHT);
// 绘制草地
if (dayMode) {
ctx.fillStyle = '#2E8B57';
} else {
ctx.fillStyle = '#1d5d2b';
}
ctx.fillRect(0, canvas.height - GROUND_HEIGHT, canvas.width, 20);
// 绘制游戏元素
bird.draw();
bird.update();
// 处理管道
if (gameState === 'playing') {
addPipe();
}
for (let i = 0; i < pipes.length; i++) {
pipes[i].draw();
if (gameState === 'playing') {
pipes[i].update();
}
// 移除屏幕外的管道
if (pipes[i].isOffScreen()) {
pipes.splice(i, 1);
i--;
}
}
// 游戏状态文本
if (gameState === 'start') {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = 'bold 48px Arial';
ctx.fillStyle = 'white';
ctx.textAlign = 'center';
ctx.fillText('像素鸟复刻版', canvas.width / 2, canvas.height / 2 - 40);
ctx.font = '20px Arial';
ctx.fillText('点击屏幕或按空格键开始游戏', canvas.width / 2, canvas.height / 2 + 20);
ctx.fillText('↑ 使用金币在商店购买新皮肤', canvas.width / 2, canvas.height / 2 + 60);
}
if (gameState === 'gameover') {
ctx.font = 'bold 36px Arial';
ctx.fillStyle = '#ff3333';
ctx.textAlign = 'center';
ctx.fillText('游戏结束!', canvas.width / 2, canvas.height / 2 - 20);
ctx.font = 'bold 28px Arial';
ctx.fillStyle = 'white';
ctx.fillText(`最终分数: ${score}`, canvas.width / 2, canvas.height / 2 + 30);
}
requestAnimationFrame(gameLoop);
}
// 事件监听
function initEventListeners() {
// 点击或空格键跳跃
canvas.addEventListener('click', () => {
bird.jump();
});
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
bird.jump();
}
});
// 切换昼夜主题
themeToggleBtn.addEventListener('click', () => {
dayMode = !dayMode;
themeToggleBtn.textContent = dayMode ? '切换夜晚' : '切换白天';
});
// 打开皮肤商店
skinShopBtn.addEventListener('click', () => {
skinShop.classList.add('active');
renderSkinShop();
});
// 关闭皮肤商店
closeModal.addEventListener('click', () => {
skinShop.classList.remove('active');
});
// 点击模态框外部关闭
skinShop.addEventListener('click', (e) => {
if (e.target === skinShop) {
skinShop.classList.remove('active');
}
});
// 开始游戏按钮
startBtn.addEventListener('click', startGame);
}
// 渲染皮肤商店
function renderSkinShop() {
skinContainer.innerHTML = '';
skins.forEach(skin => {
const skinCard = document.createElement('div');
skinCard.className = `skin-card ${skin.id === selectedSkin ? 'selected' : ''} ${!skin.unlocked ? 'locked' : ''}`;
skinCard.dataset.skin = skin.id;
skinCard.innerHTML = `
<div class="skin-preview" style="background-color: ${skin.id === 'green' ? '#4CAF50' :
skin.id === 'winter' ? '#A4DEF9' :
skin.id === 'desert' ? '#DEB887' :
skin.id === 'candy' ? '#FF9AA2' :
skin.id === 'gold' ? '#FFD700' : '#B9F2FF'}"></div>
<div class="skin-name">${skin.name}</div>
${!skin.unlocked ? `<div class="skin-price">${skin.price} 金币</div>` : ''}
`;
if (skin.unlocked || coins >= skin.price) {
skinCard.addEventListener('click', () => {
if (!skin.unlocked && coins < skin.price) return;
document.querySelectorAll('.skin-card').forEach(card => {
card.classList.remove('selected');
});
skinCard.classList.add('selected');
selectedSkin = skin.id;
});
}
skinContainer.appendChild(skinCard);
});
}
// 购买皮肤按钮事件
buySkinBtn.addEventListener('click', () => {
const skin = skins.find(s => s.id === selectedSkin);
// 如果皮肤已解锁,直接应用
if (skin.unlocked) {
skinShop.classList.remove('active');
return;
}
// 如果金币足够
if (coins >= skin.price) {
coins -= skin.price;
coinsElement.textContent = coins;
skin.unlocked = true;
renderSkinShop();
// 显示通知
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
}, 2000);
} else {
alert('金币不足!');
}
});
// 初始化
function init() {
initEventListeners();
gameLoop();
}
// 启动游戏
window.onload = init;
</script>
</body>
</html>