agent-Specialization/users/jojo/project/snake_game/snake_game_v2.html
2025-11-14 16:44:12 +08:00

385 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>
body {
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #333;
font-family: Arial, sans-serif;
}
.game-container {
text-align: center;
}
canvas {
border: 2px solid #fff;
background-color: #111;
}
.info {
color: #fff;
margin: 10px 0;
font-size: 18px;
}
.controls {
margin-top: 20px;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin: 0 5px;
}
button:hover {
background-color: #45a049;
}
button:disabled {
background-color: #666;
cursor: not-allowed;
}
</style>
</head>
<body>
<div class="game-container">
<div class="info">
<div>得分: <span id="score">0</span></div>
<div>蛇长度: <span id="length">1</span></div>
<div>游戏状态: <span id="status">准备开始</span></div>
</div>
<canvas id="gameCanvas" width="600" height="600"></canvas>
<div class="controls">
<button id="startBtn">开始游戏</button>
<button id="pauseBtn" disabled>暂停</button>
<button id="resetBtn">重置</button>
</div>
</div>
<script>
class SnakeGame {
constructor() {
this.canvas = document.getElementById('gameCanvas');
this.ctx = this.canvas.getContext('2d');
this.gridSize = 20;
this.tileCount = this.canvas.width / this.gridSize;
this.reset();
this.setupEventListeners();
}
reset() {
this.snake = [
{x: 10, y: 10}
];
this.direction = {x: 0, y: 0};
this.apple = this.generateApple();
this.score = 0;
this.gameRunning = false;
this.gamePaused = false;
this.gameLoop = null;
this.speed = 100;
this.updateUI();
this.draw();
}
generateApple() {
let apple;
do {
apple = {
x: Math.floor(Math.random() * this.tileCount),
y: Math.floor(Math.random() * this.tileCount)
};
} while (this.snake.some(segment => segment.x === apple.x && segment.y === apple.y));
return apple;
}
setupEventListeners() {
document.getElementById('startBtn').addEventListener('click', () => this.start());
document.getElementById('pauseBtn').addEventListener('click', () => this.togglePause());
document.getElementById('resetBtn').addEventListener('click', () => this.reset());
}
start() {
if (!this.gameRunning) {
this.gameRunning = true;
this.gamePaused = false;
document.getElementById('startBtn').disabled = true;
document.getElementById('pauseBtn').disabled = false;
this.gameStep();
}
}
togglePause() {
if (this.gameRunning) {
this.gamePaused = !this.gamePaused;
document.getElementById('pauseBtn').textContent = this.gamePaused ? '继续' : '暂停';
if (!this.gamePaused) {
this.gameStep();
}
}
}
gameStep() {
if (!this.gameRunning || this.gamePaused) return;
this.moveSnake();
if (this.checkCollision()) {
this.gameOver();
return;
}
this.checkApple();
this.draw();
this.updateUI();
// 使用改进的AI控制蛇的移动
this.autoMove();
setTimeout(() => this.gameStep(), this.speed);
}
autoMove() {
// 改进的AI优先保持直线移动减少之字形路线
const head = this.snake[0];
const dx = this.apple.x - head.x;
const dy = this.apple.y - head.y;
// 如果当前方向是安全的且朝着苹果的大致方向,保持当前方向
const nextX = head.x + this.direction.x;
const nextY = head.y + this.direction.y;
if (this.isSafeMove(nextX, nextY) && this.isMovingTowardsApple(this.direction, dx, dy)) {
return; // 保持当前方向,走直线
}
// 否则,寻找最佳新方向
const directions = this.getPrioritizedDirections(dx, dy);
for (let dir of directions) {
const testX = head.x + dir.x;
const testY = head.y + dir.y;
if (this.isSafeMove(testX, testY)) {
this.direction = dir;
return;
}
}
// 如果没有找到安全方向,使用备用安全方向
this.findSafeDirection(head);
}
isMovingTowardsApple(direction, dx, dy) {
// 检查当前方向是否朝着苹果的大致方向
if (dx > 0 && direction.x > 0) return true; // 苹果在右,向右移动
if (dx < 0 && direction.x < 0) return true; // 苹果在左,向左移动
if (dy > 0 && direction.y > 0) return true; // 苹果在下,向下移动
if (dy < 0 && direction.y < 0) return true; // 苹果在上,向上移动
return false;
}
getPrioritizedDirections(dx, dy) {
// 根据苹果位置,返回优先级排序的方向
const directions = [];
// 确定主要方向
let primaryHorizontal = dx > 0 ? {x: 1, y: 0} : {x: -1, y: 0};
let primaryVertical = dy > 0 ? {x: 0, y: 1} : {x: 0, y: -1};
// 根据距离决定优先级,但避免频繁改变方向
if (Math.abs(dx) > Math.abs(dy)) {
// 水平距离更大,优先水平移动
directions.push(primaryHorizontal);
directions.push(primaryVertical);
} else if (Math.abs(dy) > Math.abs(dx)) {
// 垂直距离更大,优先垂直移动
directions.push(primaryVertical);
directions.push(primaryHorizontal);
} else {
// 距离相等,保持当前方向优先
if (this.direction.x !== 0) {
directions.push(primaryHorizontal);
directions.push(primaryVertical);
} else {
directions.push(primaryVertical);
directions.push(primaryHorizontal);
}
}
// 添加相反方向(最低优先级)
directions.push({x: -primaryHorizontal.x, y: -primaryHorizontal.y});
directions.push({x: -primaryVertical.x, y: -primaryVertical.y});
return directions;
}
isSafeMove(x, y) {
// 检查是否会撞墙
if (x < 0 || x >= this.tileCount || y < 0 || y >= this.tileCount) {
return false;
}
// 检查是否会撞到自己(除了尾巴)
for (let i = 0; i < this.snake.length - 1; i++) {
if (this.snake[i].x === x && this.snake[i].y === y) {
return false;
}
}
return true;
}
findSafeDirection(head) {
// 尝试四个方向,找到安全的方向
const directions = [
{x: 1, y: 0}, // 右
{x: -1, y: 0}, // 左
{x: 0, y: 1}, // 下
{x: 0, y: -1} // 上
];
for (let dir of directions) {
const nextX = head.x + dir.x;
const nextY = head.y + dir.y;
if (this.isSafeMove(nextX, nextY)) {
this.direction = dir;
return;
}
}
// 如果没有安全方向,保持当前方向(游戏即将结束)
}
moveSnake() {
const head = {x: this.snake[0].x + this.direction.x, y: this.snake[0].y + this.direction.y};
this.snake.unshift(head);
// 如果没有吃到苹果,移除尾巴
if (head.x !== this.apple.x || head.y !== this.apple.y) {
this.snake.pop();
}
}
checkCollision() {
const head = this.snake[0];
// 撞墙检测
if (head.x < 0 || head.x >= this.tileCount || head.y < 0 || head.y >= this.tileCount) {
return true;
}
// 撞到自己检测
for (let i = 1; i < this.snake.length; i++) {
if (head.x === this.snake[i].x && head.y === this.snake[i].y) {
return true;
}
}
return false;
}
checkApple() {
const head = this.snake[0];
if (head.x === this.apple.x && head.y === this.apple.y) {
this.score += 10;
this.apple = this.generateApple();
// 检查是否填满整个地图
if (this.snake.length >= this.tileCount * this.tileCount) {
this.gameWin();
}
}
}
gameWin() {
this.gameRunning = false;
document.getElementById('status').textContent = '恭喜!蛇已铺满整个地图!';
document.getElementById('startBtn').disabled = false;
document.getElementById('pauseBtn').disabled = true;
}
gameOver() {
this.gameRunning = false;
document.getElementById('status').textContent = '游戏结束';
document.getElementById('startBtn').disabled = false;
document.getElementById('pauseBtn').disabled = true;
}
draw() {
// 清空画布
this.ctx.fillStyle = '#111';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// 画蛇
this.ctx.fillStyle = '#4CAF50';
for (let i = 0; i < this.snake.length; i++) {
const segment = this.snake[i];
this.ctx.fillRect(segment.x * this.gridSize, segment.y * this.gridSize, this.gridSize - 2, this.gridSize - 2);
// 蛇头用不同颜色
if (i === 0) {
this.ctx.fillStyle = '#81C784';
}
}
// 画苹果
this.ctx.fillStyle = '#FF5722';
this.ctx.fillRect(this.apple.x * this.gridSize, this.apple.y * this.gridSize, this.gridSize - 2, this.gridSize - 2);
// 画网格
this.ctx.strokeStyle = '#333';
this.ctx.lineWidth = 1;
for (let i = 0; i <= this.tileCount; i++) {
this.ctx.beginPath();
this.ctx.moveTo(i * this.gridSize, 0);
this.ctx.lineTo(i * this.gridSize, this.canvas.height);
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(0, i * this.gridSize);
this.ctx.lineTo(this.canvas.width, i * this.gridSize);
this.ctx.stroke();
}
}
updateUI() {
document.getElementById('score').textContent = this.score;
document.getElementById('length').textContent = this.snake.length;
if (this.gameRunning && !this.gamePaused) {
document.getElementById('status').textContent = '游戏进行中';
} else if (this.gamePaused) {
document.getElementById('status').textContent = '游戏暂停';
} else if (!this.gameRunning && this.snake.length > 1) {
document.getElementById('status').textContent = '游戏结束';
}
}
}
// 初始化游戏
window.addEventListener('DOMContentLoaded', () => {
new SnakeGame();
});
</script>
</body>
</html>