Files
blackbird/fsys/public/games/game3.html
T
2026-08-08 19:09:36 +08:00

707 lines
22 KiB
HTML

<!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 {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
color: white;
overflow-x: hidden;
padding: 20px;
}
.container {
max-width: 800px;
width: 100%;
text-align: center;
}
h1 {
font-size: 2.8rem;
margin-bottom: 10px;
text-shadow: 0 0 10px #00ff00, 0 0 20px #00ff00;
letter-spacing: 2px;
background: linear-gradient(to right, #00ff00, #ffff00);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.subtitle {
font-size: 1.1rem;
margin-bottom: 15px;
color: #a0ffa0;
}
.game-container {
position: relative;
margin: 15px auto;
border: 3px solid #00ff00;
border-radius: 10px;
box-shadow: 0 0 20px #00ff00, inset 0 0 20px rgba(0, 255, 0, 0.1);
overflow: hidden;
max-width: 600px;
}
#gameCanvas {
background: #000;
display: block;
margin: 0 auto;
width: 100%;
max-width: 600px;
}
.game-ui {
display: flex;
justify-content: space-between;
margin: 10px 0;
padding: 12px;
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
border: 1px solid #00ff00;
flex-wrap: wrap;
}
.ui-item {
font-size: 1.1rem;
font-weight: bold;
text-shadow: 0 0 5px #00ff00;
margin: 5px 0;
}
.controls {
display: flex;
justify-content: center;
gap: 10px;
margin: 15px 0;
flex-wrap: wrap;
}
button {
background: linear-gradient(135deg, #00ff00, #ffff00);
border: none;
padding: 10px 20px;
font-size: 1rem;
border-radius: 50px;
cursor: pointer;
color: #000;
font-weight: bold;
box-shadow: 0 0 15px rgba(0, 255, 0, 0.7);
transition: all 0.3s ease;
min-width: 120px;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 0 20px rgba(0, 255, 0, 0.9);
}
button:active {
transform: translateY(1px);
}
button:disabled {
background: #555;
color: #888;
box-shadow: none;
cursor: not-allowed;
}
.instructions {
margin-top: 20px;
padding: 15px;
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
border: 1px solid #00ff00;
max-width: 600px;
}
.instructions h3 {
color: #00ff00;
margin-bottom: 10px;
font-size: 1.3rem;
}
.instructions p {
margin: 8px 0;
color: #a0ffa0;
font-size: 0.95rem;
line-height: 1.4;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
padding: 25px;
border-radius: 15px;
border: 2px solid #ff0000;
text-align: center;
box-shadow: 0 0 30px #ff0000;
z-index: 10;
display: none;
width: 85%;
max-width: 350px;
}
.game-over h2 {
font-size: 1.8rem;
color: #ff0000;
margin-bottom: 12px;
text-shadow: 0 0 10px #ff0000;
}
.game-over p {
font-size: 1.1rem;
margin: 8px 0;
}
.mobile-controls {
display: none;
margin-top: 15px;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 8px;
max-width: 180px;
}
.mobile-controls button {
width: 55px;
height: 55px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3rem;
padding: 0;
min-width: auto;
}
.mobile-controls .up {
grid-column: 2;
grid-row: 1;
}
.mobile-controls .left {
grid-column: 1;
grid-row: 2;
}
.mobile-controls .right {
grid-column: 3;
grid-row: 2;
}
.mobile-controls .down {
grid-column: 2;
grid-row: 3;
}
@media (max-width: 700px) {
h1 {
font-size: 2.2rem;
}
.game-ui {
flex-direction: column;
gap: 8px;
}
.controls {
flex-direction: column;
align-items: center;
gap: 8px;
}
button {
width: 100%;
max-width: 220px;
padding: 8px 15px;
}
.mobile-controls {
display: grid;
}
.instructions {
margin-top: 15px;
padding: 12px;
}
}
@media (max-width: 500px) {
h1 {
font-size: 1.8rem;
}
.subtitle {
font-size: 0.95rem;
}
.ui-item {
font-size: 1rem;
}
.game-over h2 {
font-size: 1.5rem;
}
.game-over p {
font-size: 1rem;
}
.instructions h3 {
font-size: 1.2rem;
}
.instructions p {
font-size: 0.9rem;
}
}
@media (max-width: 400px) {
body {
padding: 15px;
}
h1 {
font-size: 1.6rem;
}
.game-container {
margin: 10px auto;
}
.controls {
margin: 10px 0;
}
button {
font-size: 0.9rem;
padding: 7px 12px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>贪吃蛇大作战</h1>
<p class="subtitle">控制小蛇吃食物,变得越来越长!</p>
<div class="game-ui">
<div class="ui-item">分数: <span id="score">0</span></div>
<div class="ui-item">长度: <span id="length">1</span></div>
<div class="ui-item">速度: <span id="speed">1</span></div>
</div>
<div class="game-container">
<canvas id="gameCanvas" width="600" height="400"></canvas>
<div class="game-over" id="gameOver">
<h2>游戏结束</h2>
<p>你的最终分数: <span id="finalScore">0</span></p>
<p>蛇的长度: <span id="finalLength">0</span></p>
<p id="gameMessage">再试一次,创造新纪录!</p>
<button id="restartBtn">重新开始</button>
</div>
</div>
<div class="mobile-controls">
<button class="up">↑</button>
<button class="left">←</button>
<button class="right">→</button>
<button class="down">↓</button>
</div>
<div class="controls">
<button id="startBtn">开始游戏</button>
<button id="pauseBtn">暂停游戏</button>
<button id="speedUpBtn">加速</button>
<button id="speedDownBtn">减速</button>
</div>
<div class="instructions">
<h3>游戏说明</h3>
<p>使用方向键或屏幕按钮控制蛇的移动方向</p>
<p>吃到食物可以增加蛇的长度和得分</p>
<p>撞到墙壁或自己的身体会导致游戏结束</p>
<p>每得100分速度会增加一级</p>
<p>看看你能让蛇变得多长!</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const restartBtn = document.getElementById('restartBtn');
const speedUpBtn = document.getElementById('speedUpBtn');
const speedDownBtn = document.getElementById('speedDownBtn');
const scoreEl = document.getElementById('score');
const lengthEl = document.getElementById('length');
const speedEl = document.getElementById('speed');
const gameOverEl = document.getElementById('gameOver');
const finalScoreEl = document.getElementById('finalScore');
const finalLengthEl = document.getElementById('finalLength');
const gameMessageEl = document.getElementById('gameMessage');
// 移动控制按钮
const upBtn = document.querySelector('.mobile-controls .up');
const leftBtn = document.querySelector('.mobile-controls .left');
const rightBtn = document.querySelector('.mobile-controls .right');
const downBtn = document.querySelector('.mobile-controls .down');
// 游戏配置
const gridSize = 20;
const gridWidth = canvas.width / gridSize;
const gridHeight = canvas.height / gridSize;
// 游戏状态
let game = {
running: false,
paused: false,
score: 0,
speed: 1,
baseSpeed: 8,
gameLoop: null
};
// 蛇的状态
let snake = {
body: [],
direction: 'right',
nextDirection: 'right',
color: '#00ff00',
headColor: '#ffff00'
};
// 食物状态
let food = {
x: 0,
y: 0,
color: '#ff0000'
};
// 初始化游戏
function initGame() {
// 初始化蛇
snake.body = [
{x: Math.floor(gridWidth / 2), y: Math.floor(gridHeight / 2)}
];
snake.direction = 'right';
snake.nextDirection = 'right';
// 生成第一个食物
generateFood();
// 重置游戏状态
game.running = true;
game.paused = false;
game.score = 0;
game.speed = 1;
updateUI();
gameOverEl.style.display = 'none';
pauseBtn.textContent = '暂停游戏';
// 开始游戏循环
if (game.gameLoop) clearInterval(game.gameLoop);
game.gameLoop = setInterval(updateGame, 1000 / (game.baseSpeed * game.speed));
// 初始绘制
drawGame();
}
// 生成食物
function generateFood() {
let newFoodPosition;
let foodOnSnake;
do {
foodOnSnake = false;
newFoodPosition = {
x: Math.floor(Math.random() * gridWidth),
y: Math.floor(Math.random() * gridHeight)
};
// 检查食物是否生成在蛇身上
for (let segment of snake.body) {
if (segment.x === newFoodPosition.x && segment.y === newFoodPosition.y) {
foodOnSnake = true;
break;
}
}
} while (foodOnSnake);
food.x = newFoodPosition.x;
food.y = newFoodPosition.y;
}
// 更新游戏状态
function updateGame() {
if (!game.running || game.paused) return;
// 更新蛇的方向
snake.direction = snake.nextDirection;
// 计算新的头部位置
const head = {...snake.body[0]};
switch (snake.direction) {
case 'up':
head.y -= 1;
break;
case 'down':
head.y += 1;
break;
case 'left':
head.x -= 1;
break;
case 'right':
head.x += 1;
break;
}
// 检查游戏结束条件
if (checkCollision(head)) {
endGame();
return;
}
// 添加新的头部
snake.body.unshift(head);
// 检查是否吃到食物
if (head.x === food.x && head.y === food.y) {
// 吃到食物,增加分数
game.score += 10;
// 每100分增加速度
if (game.score % 100 === 0) {
game.speed = Math.min(game.speed + 0.5, 5);
clearInterval(game.gameLoop);
game.gameLoop = setInterval(updateGame, 1000 / (game.baseSpeed * game.speed));
}
// 生成新食物
generateFood();
} else {
// 没吃到食物,移除尾部
snake.body.pop();
}
// 绘制游戏
drawGame();
updateUI();
}
// 检查碰撞
function checkCollision(head) {
// 检查墙壁碰撞
if (head.x < 0 || head.x >= gridWidth || head.y < 0 || head.y >= gridHeight) {
return true;
}
// 检查自身碰撞
for (let i = 1; i < snake.body.length; i++) {
if (head.x === snake.body[i].x && head.y === snake.body[i].y) {
return true;
}
}
return false;
}
// 绘制游戏
function drawGame() {
// 清空画布
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制网格
ctx.strokeStyle = '#222';
ctx.lineWidth = 0.5;
for (let x = 0; x < canvas.width; x += gridSize) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
for (let y = 0; y < canvas.height; y += gridSize) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
// 绘制食物
ctx.fillStyle = food.color;
ctx.beginPath();
ctx.arc(
food.x * gridSize + gridSize / 2,
food.y * gridSize + gridSize / 2,
gridSize / 2 - 1,
0,
Math.PI * 2
);
ctx.fill();
// 绘制蛇
snake.body.forEach((segment, index) => {
if (index === 0) {
// 蛇头
ctx.fillStyle = snake.headColor;
} else {
// 蛇身
ctx.fillStyle = snake.color;
}
ctx.fillRect(
segment.x * gridSize + 1,
segment.y * gridSize + 1,
gridSize - 2,
gridSize - 2
);
// 绘制蛇身圆角
ctx.fillStyle = index === 0 ? snake.headColor : snake.color;
ctx.beginPath();
ctx.arc(
segment.x * gridSize + gridSize / 2,
segment.y * gridSize + gridSize / 2,
gridSize / 2 - 1,
0,
Math.PI * 2
);
ctx.fill();
});
}
// 更新UI
function updateUI() {
scoreEl.textContent = game.score;
lengthEl.textContent = snake.body.length;
speedEl.textContent = game.speed.toFixed(1);
}
// 游戏结束
function endGame() {
game.running = false;
clearInterval(game.gameLoop);
finalScoreEl.textContent = game.score;
finalLengthEl.textContent = snake.body.length;
// 根据分数给出不同消息
if (game.score >= 200) {
gameMessageEl.textContent = "太厉害了!你是贪吃蛇大师!";
} else if (game.score >= 100) {
gameMessageEl.textContent = "很棒!继续努力!";
} else {
gameMessageEl.textContent = "再试一次,创造新纪录!";
}
gameOverEl.style.display = 'block';
}
// 改变方向
function changeDirection(newDirection) {
// 防止直接反向移动
if (
(newDirection === 'up' && snake.direction !== 'down') ||
(newDirection === 'down' && snake.direction !== 'up') ||
(newDirection === 'left' && snake.direction !== 'right') ||
(newDirection === 'right' && snake.direction !== 'left')
) {
snake.nextDirection = newDirection;
}
}
// 改变速度
function changeSpeed(change) {
if (!game.running) return;
game.speed = Math.max(0.5, Math.min(game.speed + change, 5));
speedEl.textContent = game.speed.toFixed(1);
clearInterval(game.gameLoop);
game.gameLoop = setInterval(updateGame, 1000 / (game.baseSpeed * game.speed));
}
// 事件监听
window.addEventListener('keydown', (e) => {
if (!game.running) return;
switch (e.key) {
case 'ArrowUp':
e.preventDefault();
changeDirection('up');
break;
case 'ArrowDown':
e.preventDefault();
changeDirection('down');
break;
case 'ArrowLeft':
e.preventDefault();
changeDirection('left');
break;
case 'ArrowRight':
e.preventDefault();
changeDirection('right');
break;
}
});
// 移动控制按钮事件
upBtn.addEventListener('click', () => changeDirection('up'));
downBtn.addEventListener('click', () => changeDirection('down'));
leftBtn.addEventListener('click', () => changeDirection('left'));
rightBtn.addEventListener('click', () => changeDirection('right'));
// 控制按钮事件
startBtn.addEventListener('click', () => {
if (!game.running) {
initGame();
startBtn.disabled = true;
setTimeout(() => {
startBtn.disabled = false;
}, 1000);
}
});
pauseBtn.addEventListener('click', () => {
if (game.running) {
game.paused = !game.paused;
pauseBtn.textContent = game.paused ? '继续游戏' : '暂停游戏';
}
});
restartBtn.addEventListener('click', () => {
initGame();
});
speedUpBtn.addEventListener('click', () => changeSpeed(0.5));
speedDownBtn.addEventListener('click', () => changeSpeed(-0.5));
// 初始绘制
drawGame();
});
</script>
</body>
</html>