现代贪吃蛇游戏的进化:从经典玩法到多人在线体验

发布于:2025-08-29 ⋅ 阅读:(19) ⋅ 点赞:(0)

Hi,我是前端人类学(之前叫布兰妮甜)!
贪吃蛇游戏自1976年诞生以来,已经从简单的像素游戏发展成为具有丰富功能的现代游戏体验。本文将通过一个功能增强版的贪吃蛇游戏,探讨如何将经典游戏概念与现代Web技术相结合,创造出既保留经典玩法又具备现代特性的游戏体验。



一、技术架构与设计理念

这个增强版贪吃蛇游戏采用HTML5 Canvas作为渲染核心,结合现代CSS布局和JavaScript模块化设计,实现了以下核心功能:

  1. 基础游戏机制:蛇的移动、食物生成、碰撞检测
  2. 多人游戏模式:实时多玩家支持与竞争机制
  3. 成就系统:进度追踪与玩家激励
  4. 关卡编辑器:用户生成内容支持
  5. 资源管理系统:自定义皮肤与背景

二、多人在线模式的实现

多人在线功能是本项目的核心创新之一。通过模拟的网络通信机制,游戏支持2-4名玩家同时参与,并提供三种不同的游戏模式:

// 多人在线模式状态
let multiplayerState = {
  players: [
    { id: 1, name: '玩家1', score: 0, color: '#4CAF50', alive: true, snake: [], dx: 1, dy: 0 },
    { id: 2, name: '玩家2', score: 0, color: '#FF5252', alive: true, snake: [], dx: 1, dy: 0 },
    { id: 3, name: '玩家3', score: 0, color: '#FFC107', alive: true, snake: [], dx: 1, dy: 0 },
    { id: 4, name: '玩家4', score: 0, color: '#9C27B0', alive: true, snake: [], dx: 1, dy: 0 }
  ],
  mode: 'competition',
  status: 'lobby',
  food: []
}

这种设计允许玩家根据偏好选择不同的游戏体验,从合作共嬴到激烈竞争,大大扩展了游戏的可玩性。

三、成就系统的心理激励

成就系统通过提供明确的目标和奖励,有效增强了玩家的参与度和长期投入:

// 成就数据结构
const achievements = [
    {
        id: "first_blood",
        name: "初出茅庐",
        description: "获得100分",
        icon: "fas fa-star",
        progress: 0,
        target: 100,
        unlocked: false
    },
    {
        id: "speed_demon",
        name: "速度之王",
        description: "以最高速度游戏1分钟",
        icon: "fas fa-fire",
        progress: 0,
        target: 60,
        unlocked: false
    }
];

// 成就解锁检查
function checkAchievements() {
    achievements.forEach(achievement => {
        if (!achievement.unlocked && achievement.progress >= achievement.target) {
            unlockAchievement(achievement.id);
        }
    });
}

这种成就系统不仅提供了短期目标,还通过进度可视化给予玩家持续的正向反馈,符合游戏化设计的基本原则。

四、关卡编辑器的创意表达

关卡编辑器功能将玩家从被动的消费者转变为主动的创作者,极大地扩展了游戏的内容生命周期:

canvas.addEventListener('click', e => {
    if (!isEditing) return

    const rect = canvas.getBoundingClientRect()
    const x = e.clientX - rect.left
    const y = e.clientY - rect.top

    const gridX = Math.floor(x / gridSize)
    const gridY = Math.floor(y / gridSize)

    if (currentTool === 'wall') {
      // 添加墙壁
      obstacles.push({ x: gridX, y: gridY })
    } else if (currentTool === 'obstacle') {
      // 添加障碍物
      obstacles.push({ x: gridX, y: gridY })
    } else if (currentTool === 'erase') {
      // 删除墙壁或障碍物
      obstacles = obstacles.filter(obs => !(obs.x === gridX && obs.y === gridY))
    }

    draw()
  })

通过简单的点击交互,玩家可以创建复杂多样的游戏关卡,分享给其他玩家,形成活跃的创作者社区。

五、响应式设计与跨平台体验

游戏采用完全响应式设计,确保在不同设备上都能提供一致的用户体验:

/* 响应式布局系统 */
.container {
  width: 100%;
  max-width: 1400px;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  gap: 20px;
  margin-top: 20px;
}

@media (max-width: 900px) {
  .container {
    grid-template-columns: 1fr;
  }

  .left-panel,
  .right-panel {
    display: none;
  }

  .mobile-controls {
    display: grid;
  }
}

/* 移动端控制优化 */
.mobile-controls {
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(2, 1fr);
}

.mobile-controls button {
    height: 70px;
    font-size: 1.5rem;
}

这种设计确保从桌面电脑到移动手机,玩家都能享受完整的游戏功能,包括多人游戏和关卡编辑等高级特性。

六、完整代码实现

**页面结构(snake-game.html) **

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  <link rel="stylesheet" href="snake-game.css">
  <title>高级贪吃蛇游戏</title>
</head>

<body>
  <header>
    <h1><i class="fas fa-snake"></i> 贪吃蛇游戏 - 多人在线版</h1>
    <div class="tabs">
      <div class="tab active" data-tab="single">单人游戏</div>
      <div class="tab" data-tab="multiplayer">多人游戏</div>
      <div class="tab" data-tab="achievements">成就系统</div>
      <div class="tab" data-tab="level-editor">关卡编辑器</div>
    </div>
    <div class="game-info">
      <div class="info-box">
        <i class="fas fa-star"></i>
        <span>得分: <span id="score">0</span></span>
      </div>
      <div class="info-box">
        <i class="fas fa-tachometer-alt"></i>
        <span>速度: <span id="speed">5</span></span>
      </div>
      <div class="info-box">
        <i class="fas fa-clock"></i>
        <span>时间: <span id="time">00:00</span></span>
      </div>
    </div>
    <div class="multiplayer-status" id="multiplayerStatus">
      <div class="player-indicator">
        <div class="player-color player-1"></div>
        <span>玩家1: <span id="player1Score">0</span></span>
      </div>
      <div class="player-indicator">
        <div class="player-color player-2"></div>
        <span>玩家2: <span id="player2Score">0</span></span>
      </div>
      <div class="player-indicator">
        <div class="player-color player-3"></div>
        <span>玩家3: <span id="player3Score">0</span></span>
      </div>
      <div class="player-indicator">
        <div class="player-color player-4"></div>
        <span>玩家4: <span id="player4Score">0</span></span>
      </div>
    </div>
  </header>

  <div class="container">
    <div class="left-panel panel">
      <h3 class="section-title"><i class="fas fa-cog"></i> 游戏设置</h3>

      <div class="settings-group">
        <label for="gameSpeed">游戏速度</label>
        <input type="range" id="gameSpeed" min="1" max="10" value="5">
        <div class="range-value"><span id="speedValue">5</span>/10</div>
      </div>

      <div class="settings-group">
        <label for="gridSize">网格大小</label>
        <select id="gridSize">
          <option value="15">小 (15x15)</option>
          <option value="20" selected>中 (20x20)</option>
          <option value="25">大 (25x25)</option>
        </select>
      </div>

      <div class="settings-group">
        <label for="wallMode">墙壁模式</label>
        <select id="wallMode">
          <option value="solid">实心墙 (游戏结束)</option>
          <option value="pass-through">穿透 (循环边界)</option>
        </select>
      </div>

      <h3 class="section-title"><i class="fas fa-upload"></i> 上传资源</h3>

      <div class="upload-area" id="uploadBg">
        <i class="fas fa-image"></i>
        <p>上传背景</p>
        <input type="file" id="bgUpload" accept="image/*" style="display: none;">
      </div>

      <div class="upload-area" id="uploadSkin">
        <i class="fas fa-palette"></i>
        <p>上传蛇皮肤</p>
        <input type="file" id="skinUpload" accept="image/*" style="display: none;">
      </div>

      <button class="secondary" id="resetSettings">
        <i class="fas fa-undo"></i> 重置设置
      </button>
    </div>

    <div class="game-area panel">
      <canvas id="gameCanvas" width="600" height="600"></canvas>

      <div class="level-editor" id="levelEditor">
        <h3><i class="fas fa-edit"></i> 关卡编辑器</h3>
        <div class="editor-tools">
          <button id="wallTool"><i class="fas fa-wall"></i> 墙壁</button>
          <button id="obstacleTool"><i class="fas fa-mountain"></i> 障碍物</button>
          <button id="eraseTool"><i class="fas fa-eraser"></i> 擦除</button>
        </div>
        <div>
          <input type="text" id="levelName" placeholder="关卡名称">
          <button id="saveLevel"><i class="fas fa-save"></i> 保存关卡</button>
          <button id="loadLevel"><i class="fas fa-folder-open"></i> 加载关卡</button>
        </div>
      </div>

      <div class="game-over" id="gameOver">
        <h2>游戏结束!</h2>
        <p>得分: <span id="finalScore">0</span></p>
        <div class="controls">
          <button id="restartBtn">
            <i class="fas fa-redo"></i> 重新开始
          </button>
          <button class="secondary" id="menuBtn">
            <i class="fas fa-home"></i> 返回菜单
          </button>
        </div>
      </div>
    </div>

    <div class="right-panel panel">
      <div class="tab-content active" id="singleTab">
        <h3 class="section-title"><i class="fas fa-trophy"></i> 排行榜</h3>

        <ul class="leaderboard" id="leaderboard">
          <li>
            <span><span class="rank">1</span> 玩家1</span>
            <span class="score">450</span>
          </li>
          <li>
            <span><span class="rank">2</span> 玩家2</span>
            <span class="score">320</span>
          </li>
          <li>
            <span><span class="rank">3</span> 玩家3</span>
            <span class="score">280</span>
          </li>
        </ul>

        <h3 class="section-title"><i class="fas fa-gamepad"></i> 游戏控制</h3>

        <div class="controls">
          <button id="startBtn">
            <i class="fas fa-play"></i> 开始游戏
          </button>
          <button class="secondary" id="pauseBtn">
            <i class="fas fa-pause"></i> 暂停
          </button>
          <button class="accent" id="soundBtn">
            <i class="fas fa-volume-up"></i> 音效: 开
          </button>
          <button id="saveBtn">
            <i class="fas fa-save"></i> 保存设置
          </button>
        </div>

        <p style="margin-top: 15px; text-align: center;">
          使用 <i class="fas fa-arrow-up"></i> <i class="fas fa-arrow-down"></i>
          <i class="fas fa-arrow-left"></i> <i class="fas fa-arrow-right"></i> 方向键控制
        </p>
      </div>

      <div class="tab-content" id="multiplayerTab">
        <h3 class="section-title"><i class="fas fa-users"></i> 多人游戏</h3>

        <div class="settings-group">
          <label for="playerCount">玩家数量</label>
          <select id="playerCount">
            <option value="2">2 玩家</option>
            <option value="3">3 玩家</option>
            <option value="4">4 玩家</option>
          </select>
        </div>

        <div class="settings-group">
          <label for="gameMode">游戏模式</label>
          <select id="gameMode">
            <option value="coop">合作模式</option>
            <option value="competition">竞争模式</option>
            <option value="last-standing">生存模式</option>
          </select>
        </div>

        <div class="player-controls">
          <div class="player-control">
            <div class="online-indicator"></div>
            <span>玩家1</span>
            <select>
              <option value="human">人类玩家</option>
              <option value="easy">简单AI</option>
              <option value="medium">中等AI</option>
              <option value="hard">困难AI</option>
            </select>
          </div>
          <div class="player-control">
            <div class="online-indicator"></div>
            <span>玩家2</span>
            <select>
              <option value="human">人类玩家</option>
              <option value="easy">简单AI</option>
              <option value="medium">中等AI</option>
              <option value="hard">困难AI</option>
            </select>
          </div>
          <div class="player-control">
            <div class="online-indicator offline"></div>
            <span>玩家3</span>
            <select>
              <option value="none">无玩家</option>
              <option value="human">人类玩家</option>
              <option value="easy">简单AI</option>
              <option value="medium">中等AI</option>
              <option value="hard">困难AI</option>
            </select>
          </div>
          <div class="player-control">
            <div class="online-indicator offline"></div>
            <span>玩家4</span>
            <select>
              <option value="none">无玩家</option>
              <option value="human">人类玩家</option>
              <option value="easy">简单AI</option>
              <option value="medium">中等AI</option>
              <option value="hard">困难AI</option>
            </select>
          </div>
        </div>

        <button id="createLobby">
          <i class="fas fa-plus"></i> 创建房间
        </button>

        <button id="joinLobby">
          <i class="fas fa-sign-in-alt"></i> 加入房间
        </button>

        <div id="lobbyList" style="margin-top: 15px;">
          <h4>可用房间</h4>
          <ul style="list-style: none;">
            <li>房间1 (2/4玩家)</li>
            <li>房间2 (1/2玩家)</li>
          </ul>
        </div>
      </div>

      <div class="tab-content" id="achievementsTab">
        <h3 class="section-title"><i class="fas fa-trophy"></i> 成就系统</h3>

        <div class="achievements">
          <div class="achievement unlocked">
            <i class="fas fa-star"></i>
            <h4>初出茅庐</h4>
            <p>获得100分</p>
            <div class="achievement-progress">
              <div class="achievement-progress-bar" style="width: 100%"></div>
            </div>
          </div>

          <div class="achievement">
            <i class="fas fa-fire"></i>
            <h4>速度之王</h4>
            <p>以最高速度游戏1分钟</p>
            <div class="achievement-progress">
              <div class="achievement-progress-bar" style="width: 30%"></div>
            </div>
          </div>

          <div class="achievement unlocked">
            <i class="fas fa-users"></i>
            <h4>团队合作</h4>
            <p>完成一局合作模式</p>
            <div class="achievement-progress">
              <div class="achievement-progress-bar" style="width: 100%"></div>
            </div>
          </div>

          <div class="achievement">
            <i class="fas fa-ghost"></i>
            <h4>幽灵模式</h4>
            <p>在穿透模式下获得500分</p>
            <div class="achievement-progress">
              <div class="achievement-progress-bar" style="width: 65%"></div>
            </div>
          </div>

          <div class="achievement">
            <i class="fas fa-infinity"></i>
            <h4>无限挑战</h4>
            <p>蛇身长度达到50节</p>
            <div class="achievement-progress">
              <div class="achievement-progress-bar" style="width: 40%"></div>
            </div>
          </div>

          <div class="achievement">
            <i class="fas fa-crown"></i>
            <h4>贪吃蛇大师</h4>
            <p>解锁所有成就</p>
            <div class="achievement-progress">
              <div class="achievement-progress-bar" style="width: 25%"></div>
            </div>
          </div>
        </div>
      </div>

      <div class="tab-content" id="levelEditorTab">
        <h3 class="section-title"><i class="fas fa-edit"></i> 我的关卡</h3>

        <div style="margin-bottom: 15px;">
          <input type="text" placeholder="搜索关卡..." style="width: 100%;">
        </div>

        <ul class="leaderboard">
          <li>
            <span>迷宫挑战</span>
            <span><i class="fas fa-play"></i> 游玩</span>
          </li>
          <li>
            <span>极限模式</span>
            <span><i class="fas fa-play"></i> 游玩</span>
          </li>
          <li>
            <span>合作关卡</span>
            <span><i class="fas fa-play"></i> 游玩</span>
          </li>
        </ul>

        <button style="margin-top: 15px;">
          <i class="fas fa-share"></i> 分享关卡
        </button>
      </div>
    </div>
  </div>

  <div class="mobile-controls">
    <button id="upBtn"><i class="fas fa-arrow-up"></i></button>
    <button id="leftBtn"><i class="fas fa-arrow-left"></i></button>
    <button id="downBtn"><i class="fas fa-arrow-down"></i></button>
    <button id="rightBtn"><i class="fas fa-arrow-right"></i></button>
  </div>

  <script src="snake-game.js"></script>
</body>

</html>

页面样式(snake-game.css)

:root {
  --primary-color: #4CAF50;
  --secondary-color: #2196F3;
  --accent-color: #FF5722;
  --dark-color: #2c3e50;
  --light-color: #ecf0f1;
  --success-color: #2ecc71;
  --danger-color: #e74c3c;
  --warning-color: #f39c12;
  --multiplayer-color-1: #FF5252;
  --multiplayer-color-2: #FFC107;
  --multiplayer-color-3: #9C27B0;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

body {
  background: linear-gradient(135deg, var(--dark-color), #34495e);
  color: var(--light-color);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
}

.container {
  width: 100%;
  max-width: 1400px;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  gap: 20px;
  margin-top: 20px;
}

header {
  text-align: center;
  margin-bottom: 20px;
  width: 100%;
}

h1 {
  font-size: 2.5rem;
  margin-bottom: 10px;
  color: var(--primary-color);
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}

.tabs {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-bottom: 20px;
}

.tab {
  padding: 10px 20px;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s;
}

.tab.active {
  background: var(--primary-color);
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
}

.game-info {
  display: flex;
  justify-content: center;
  gap: 20px;
  margin-bottom: 15px;
}

.info-box {
  background: rgba(0, 0, 0, 0.3);
  padding: 10px 20px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.info-box i {
  font-size: 1.5rem;
  color: var(--primary-color);
}

.panel {
  background: rgba(0, 0, 0, 0.5);
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
  backdrop-filter: blur(10px);
  max-height: 80vh;
  overflow-y: auto;
}

.left-panel,
.right-panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.game-area {
  position: relative;
}

canvas {
  background-color: #1a1a2e;
  border-radius: 12px;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
  display: block;
  width: 100%;
}

.controls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

button {
  background: var(--primary-color);
  color: white;
  border: none;
  padding: 12px;
  border-radius: 8px;
  cursor: pointer;
  font-weight: bold;
  transition: all 0.3s;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

button:hover {
  background: #3e8e41;
  transform: translateY(-2px);
}

button.secondary {
  background: var(--secondary-color);
}

button.secondary:hover {
  background: #0b7dda;
}

button.accent {
  background: var(--accent-color);
}

button.accent:hover {
  background: #d84315;
}

.section-title {
  font-size: 1.2rem;
  margin-bottom: 15px;
  padding-bottom: 8px;
  border-bottom: 2px solid var(--primary-color);
  color: var(--primary-color);
}

.settings-group {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 5px;
  font-weight: 500;
}

input[type="range"] {
  width: 100%;
  margin: 10px 0;
}

.range-value {
  text-align: center;
  font-weight: bold;
  color: var(--primary-color);
}

select,
input[type="text"] {
  width: 100%;
  padding: 10px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.1);
  color: white;
  border: 1px solid rgba(255, 255, 255, 0.2);
  margin-bottom: 10px;
}

.upload-area {
  border: 2px dashed rgba(255, 255, 255, 0.3);
  border-radius: 8px;
  padding: 20px;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s;
  margin-top: 10px;
}

.upload-area:hover {
  border-color: var(--primary-color);
  background: rgba(76, 175, 80, 0.1);
}

.upload-area i {
  font-size: 2rem;
  margin-bottom: 10px;
  color: var(--primary-color);
}

.achievements {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.achievement {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 10px;
  text-align: center;
  position: relative;
}

.achievement.locked {
  opacity: 0.6;
}

.achievement i {
  font-size: 2rem;
  margin-bottom: 5px;
  color: var(--warning-color);
}

.achievement.unlocked i {
  color: gold;
}

.achievement-progress {
  height: 5px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: 3px;
  margin-top: 5px;
  overflow: hidden;
}

.achievement-progress-bar {
  height: 100%;
  background: var(--primary-color);
  border-radius: 3px;
}

.leaderboard {
  list-style: none;
}

.leaderboard li {
  padding: 12px;
  background: rgba(255, 255, 255, 0.1);
  margin-bottom: 8px;
  border-radius: 6px;
  display: flex;
  justify-content: space-between;
}

.leaderboard .rank {
  font-weight: bold;
  color: var(--primary-color);
  margin-right: 10px;
}

.leaderboard .score {
  font-weight: bold;
  color: var(--accent-color);
}

.game-over {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border-radius: 12px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s;
}

.game-over.show {
  opacity: 1;
  pointer-events: all;
}

.game-over h2 {
  font-size: 3rem;
  color: var(--danger-color);
  margin-bottom: 20px;
}

.game-over p {
  font-size: 1.5rem;
  margin-bottom: 30px;
}

.multiplayer-status {
  display: flex;
  gap: 10px;
  margin-bottom: 15px;
}

.player-indicator {
  display: flex;
  align-items: center;
  gap: 5px;
}

.player-color {
  width: 15px;
  height: 15px;
  border-radius: 50%;
}

.player-1 {
  background: var(--primary-color);
}
.player-2 {
  background: var(--multiplayer-color-1);
}
.player-3 {
  background: var(--multiplayer-color-2);
}
.player-4 {
  background: var(--multiplayer-color-3);
}

.level-editor {
  display: none;
  position: absolute;
  top: 10px;
  right: 10px;
  background: rgba(0, 0, 0, 0.7);
  padding: 10px;
  border-radius: 8px;
  z-index: 10;
}

.editor-tools {
  display: flex;
  gap: 5px;
  margin-bottom: 10px;
}

.editor-tools button {
  padding: 8px;
  font-size: 0.9rem;
}

.mobile-controls {
  display: none;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 10px;
  margin-top: 20px;
}

.mobile-controls button {
  height: 70px;
  font-size: 1.5rem;
}

.mobile-controls button:nth-child(1) {
  grid-column: 2;
  grid-row: 1;
}

.mobile-controls button:nth-child(2) {
  grid-column: 1;
  grid-row: 2;
}

.mobile-controls button:nth-child(3) {
  grid-column: 2;
  grid-row: 2;
}

.mobile-controls button:nth-child(4) {
  grid-column: 3;
  grid-row: 2;
}

/* 多人在线模式特定样式 */
.player-controls {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 15px;
}

.player-control {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 6px;
}

.player-control select {
  flex: 1;
  margin: 0;
}

.online-indicator {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--success-color);
}

.online-indicator.offline {
  background: var(--danger-color);
}

@media (max-width: 900px) {
  .container {
    grid-template-columns: 1fr;
  }

  .left-panel,
  .right-panel {
    display: none;
  }

  .mobile-controls {
    display: grid;
  }
}

业务逻辑(snake-game.js)

// 游戏主要变量
const canvas = document.getElementById('gameCanvas')
const ctx = canvas.getContext('2d')
const scoreElement = document.getElementById('score')
const speedElement = document.getElementById('speed')
const timeElement = document.getElementById('time')
const gameOverElement = document.getElementById('gameOver')
const finalScoreElement = document.getElementById('finalScore')

let gridSize = 20
let tileCount = canvas.width / gridSize
let snake = []
let food = {}
let dx = 0
let dy = 0
let score = 0
let gameSpeed = 150
let gameInterval
let isPaused = false
let isGameOver = false
let gameTime = 0
let timeInterval
let isSoundOn = true
let isMultiplayer = false
let obstacles = []
let currentTool = 'wall'
let isEditing = false

// 多人在线模式状态
let multiplayerState = {
  players: [
    { id: 1, name: '玩家1', score: 0, color: '#4CAF50', alive: true, snake: [], dx: 1, dy: 0 },
    { id: 2, name: '玩家2', score: 0, color: '#FF5252', alive: true, snake: [], dx: 1, dy: 0 },
    { id: 3, name: '玩家3', score: 0, color: '#FFC107', alive: true, snake: [], dx: 1, dy: 0 },
    { id: 4, name: '玩家4', score: 0, color: '#9C27B0', alive: true, snake: [], dx: 1, dy: 0 }
  ],
  mode: 'competition',
  status: 'lobby',
  food: []
}

// 初始化游戏
function initGame() {
  // 初始化蛇
  snake = [
    { x: 10, y: 10 },
    { x: 9, y: 10 },
    { x: 8, y: 10 }
  ]

  // 生成食物
  generateFood()

  // 生成障碍物
  generateObstacles()

  // 重置游戏状态
  score = 0
  dx = 1
  dy = 0
  gameTime = 0
  isGameOver = false

  // 更新UI
  scoreElement.textContent = score
  gameOverElement.classList.remove('show')

  // 绘制初始状态
  draw()

  // 启动计时器
  startTimer()
}

// 初始化多人游戏
function initMultiplayerGame() {
  const playerCount = parseInt(document.getElementById('playerCount').value)
  const gameMode = document.getElementById('gameMode').value

  // 设置玩家数量
  multiplayerState.players = multiplayerState.players.slice(0, playerCount)

  // 初始化每个玩家的蛇
  multiplayerState.players.forEach((player, index) => {
    const startX = 5 + index * 5
    player.snake = [
      { x: startX, y: 10 },
      { x: startX - 1, y: 10 },
      { x: startX - 2, y: 10 }
    ]
    player.score = 0
    player.alive = true

    // 设置初始方向
    player.dx = 1
    player.dy = 0
  })

  // 生成多个食物
  generateMultiplayerFood()

  // 更新玩家状态显示
  updateMultiplayerStatus()

  // 设置游戏模式
  multiplayerState.mode = gameMode
  multiplayerState.status = 'playing'

  // 开始游戏循环
  if (gameInterval) clearInterval(gameInterval)
  gameInterval = setInterval(multiplayerGameLoop, gameSpeed)
}

// 多人游戏循环
function multiplayerGameLoop() {
  if (!isPaused && multiplayerState.status === 'playing') {
    moveMultiplayerSnakes()
    drawMultiplayerGame()
    checkMultiplayerGameOver()
  }
}

// 移动所有玩家的蛇
function moveMultiplayerSnakes() {
  multiplayerState.players.forEach(player => {
    if (player.alive) {
      const head = {
        x: player.snake[0].x + player.dx,
        y: player.snake[0].y + player.dy
      }

      // 墙壁碰撞检测
      const wallMode = document.getElementById('wallMode').value
      if (wallMode === 'solid') {
        if (head.x < 0 || head.y < 0 || head.x >= tileCount || head.y >= tileCount) {
          player.alive = false
          return
        }
      } else {
        if (head.x < 0) head.x = tileCount - 1
        if (head.y < 0) head.y = tileCount - 1
        if (head.x >= tileCount) head.x = 0
        if (head.y >= tileCount) head.y = 0
      }

      // 添加到蛇头
      player.snake.unshift(head)

      // 检查是否吃到食物
      let ateFood = false
      for (let i = 0; i < multiplayerState.food.length; i++) {
        const food = multiplayerState.food[i]
        if (head.x === food.x && head.y === food.y) {
          player.score += 10
          multiplayerState.food.splice(i, 1)
          generateMultiplayerFood() // 生成新食物
          ateFood = true
          break
        }
      }

      // 如果没吃到食物,移除蛇尾
      if (!ateFood) {
        player.snake.pop()
      }

      // 检查碰撞
      checkMultiplayerCollisions(player)
    }
  })
}

// 检查多人游戏碰撞
function checkMultiplayerCollisions(player) {
  const head = player.snake[0]

  // 检查是否撞到自己
  for (let i = 1; i < player.snake.length; i++) {
    if (head.x === player.snake[i].x && head.y === player.snake[i].y) {
      player.alive = false
      return
    }
  }

  // 检查是否撞到障碍物
  for (let obs of obstacles) {
    if (head.x === obs.x && head.y === obs.y) {
      player.alive = false
      return
    }
  }

  // 检查是否撞到其他玩家
  multiplayerState.players.forEach(otherPlayer => {
    if (otherPlayer.id !== player.id && otherPlayer.alive) {
      for (let part of otherPlayer.snake) {
        if (head.x === part.x && head.y === part.y) {
          player.alive = false
          return
        }
      }
    }
  })
}

// 绘制多人游戏
function drawMultiplayerGame() {
  // 清空画布
  ctx.fillStyle = '#1a1a2e'
  ctx.fillRect(0, 0, canvas.width, canvas.height)

  // 绘制网格
  drawGrid()

  // 绘制障碍物
  drawObstacles()

  // 绘制所有玩家的蛇
  multiplayerState.players.forEach(player => {
    if (player.alive) {
      for (let i = 0; i < player.snake.length; i++) {
        const part = player.snake[i]

        if (i === 0) {
          // 蛇头
          ctx.fillStyle = player.color
        } else {
          // 蛇身
          ctx.fillStyle = shadeColor(player.color, -20)
        }

        ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize - 1, gridSize - 1)

        // 为蛇身添加圆角效果
        ctx.beginPath()
        ctx.arc(part.x * gridSize + gridSize / 2, part.y * gridSize + gridSize / 2, gridSize / 2 - 1, 0, Math.PI * 2)
        ctx.fill()
      }
    }
  })

  // 绘制食物
  multiplayerState.food.forEach(food => {
    ctx.fillStyle = '#FF5252'
    ctx.beginPath()
    ctx.arc(food.x * gridSize + gridSize / 2, food.y * gridSize + gridSize / 2, gridSize / 2 - 1, 0, Math.PI * 2)
    ctx.fill()
  })

  // 更新玩家分数显示
  updateMultiplayerStatus()
}

// 生成多人游戏食物
function generateMultiplayerFood() {
  multiplayerState.food = []
  const foodCount = multiplayerState.players.length * 2

  for (let i = 0; i < foodCount; i++) {
    const food = {
      x: Math.floor(Math.random() * tileCount),
      y: Math.floor(Math.random() * tileCount)
    }

    // 确保食物不会出现在蛇身上或障碍物上
    let validPosition = true

    multiplayerState.players.forEach(player => {
      for (let part of player.snake) {
        if (part.x === food.x && part.y === food.y) {
          validPosition = false
        }
      }
    })

    for (let obs of obstacles) {
      if (obs.x === food.x && obs.y === food.y) {
        validPosition = false
      }
    }

    if (validPosition) {
      multiplayerState.food.push(food)
    } else {
      i-- // 重试
    }
  }
}

// 检查多人游戏是否结束
function checkMultiplayerGameOver() {
  let alivePlayers = 0
  multiplayerState.players.forEach(player => {
    if (player.alive) alivePlayers++
  })

  if (alivePlayers <= 1) {
    multiplayerState.status = 'finished'

    // 显示游戏结束画面
    finalScoreElement.textContent = `玩家${multiplayerState.players.findIndex(p => p.alive) + 1}获胜!`
    gameOverElement.classList.add('show')

    // 播放游戏结束音效
    if (isSoundOn) {
      playSound('gameover')
    }
  }
}

// 更新多人游戏状态显示
function updateMultiplayerStatus() {
  multiplayerState.players.forEach((player, index) => {
    document.getElementById(`player${index + 1}Score`).textContent = player.score
  })
}

// 工具函数:调整颜色亮度
function shadeColor(color, percent) {
  let R = parseInt(color.substring(1, 3), 16)
  let G = parseInt(color.substring(3, 5), 16)
  let B = parseInt(color.substring(5, 7), 16)

  R = parseInt((R * (100 + percent)) / 100)
  G = parseInt((G * (100 + percent)) / 100)
  B = parseInt((B * (100 + percent)) / 100)

  R = R < 255 ? R : 255
  G = G < 255 ? G : 255
  B = B < 255 ? B : 255

  R = R < 0 ? 0 : R
  G = G < 0 ? 0 : G
  B = B < 0 ? 0 : B

  const RR = R.toString(16).length === 1 ? '0' + R.toString(16) : R.toString(16)
  const GG = G.toString(16).length === 1 ? '0' + G.toString(16) : G.toString(16)
  const BB = B.toString(16).length === 1 ? '0' + B.toString(16) : B.toString(16)

  return '#' + RR + GG + BB
}

// 生成食物
function generateFood() {
  food = {
    x: Math.floor(Math.random() * tileCount),
    y: Math.floor(Math.random() * tileCount)
  }

  // 确保食物不会出现在蛇身上或障碍物上
  for (let part of snake) {
    if (part.x === food.x && part.y === food.y) {
      generateFood()
      return
    }
  }

  for (let obs of obstacles) {
    if (obs.x === food.x && obs.y === food.y) {
      generateFood()
      return
    }
  }
}

// 生成障碍物
function generateObstacles() {
  obstacles = []
  const obstacleCount = Math.floor(tileCount * 0.1) // 10%的格子作为障碍物

  for (let i = 0; i < obstacleCount; i++) {
    let obstacle = {
      x: Math.floor(Math.random() * tileCount),
      y: Math.floor(Math.random() * tileCount)
    }

    // 确保障碍物不会出现在蛇的初始位置或食物上
    let validPosition = true
    for (let part of snake) {
      if (part.x === obstacle.x && part.y === obstacle.y) {
        validPosition = false
        break
      }
    }

    if (obstacle.x === food.x && obstacle.y === food.y) {
      validPosition = false
    }

    if (validPosition) {
      obstacles.push(obstacle)
    } else {
      i-- // 重试
    }
  }
}

// 绘制游戏
function draw() {
  // 清空画布
  ctx.fillStyle = '#1a1a2e'
  ctx.fillRect(0, 0, canvas.width, canvas.height)

  // 绘制网格
  drawGrid()

  // 绘制障碍物
  drawObstacles()

  // 绘制蛇
  for (let i = 0; i < snake.length; i++) {
    const part = snake[i]

    // 蛇头用不同颜色
    if (i === 0) {
      ctx.fillStyle = '#4CAF50'
    } else {
      ctx.fillStyle = '#8BC34A'
    }

    ctx.fillRect(part.x * gridSize, part.y * gridSize, gridSize - 1, gridSize - 1)

    // 为蛇身添加圆角效果
    ctx.beginPath()
    ctx.arc(part.x * gridSize + gridSize / 2, part.y * gridSize + gridSize / 2, gridSize / 2 - 1, 0, Math.PI * 2)
    ctx.fill()
  }

  // 绘制食物
  ctx.fillStyle = '#FF5252'
  ctx.beginPath()
  ctx.arc(food.x * gridSize + gridSize / 2, food.y * gridSize + gridSize / 2, gridSize / 2 - 1, 0, Math.PI * 2)
  ctx.fill()
}

// 绘制网格
function drawGrid() {
  ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)'
  ctx.lineWidth = 0.5

  for (let i = 0; i < tileCount; i++) {
    // 垂直线
    ctx.beginPath()
    ctx.moveTo(i * gridSize, 0)
    ctx.lineTo(i * gridSize, canvas.height)
    ctx.stroke()

    // 水平线
    ctx.beginPath()
    ctx.moveTo(0, i * gridSize)
    ctx.lineTo(canvas.width, i * gridSize)
    ctx.stroke()
  }
}

// 绘制障碍物
function drawObstacles() {
  ctx.fillStyle = '#607D8B'
  for (let obs of obstacles) {
    ctx.fillRect(obs.x * gridSize, obs.y * gridSize, gridSize - 1, gridSize - 1)

    // 添加纹理效果
    ctx.fillStyle = '#455A64'
    ctx.fillRect(obs.x * gridSize + 2, obs.y * gridSize + 2, gridSize - 5, gridSize - 5)
    ctx.fillStyle = '#607D8B'
  }
}

// 移动蛇
function moveSnake() {
  // 计算新的头部位置
  const head = { x: snake[0].x + dx, y: snake[0].y + dy }

  // 检查墙壁模式
  const wallMode = document.getElementById('wallMode').value
  if (wallMode === 'solid') {
    // 实心墙模式 - 检查是否撞墙
    if (head.x < 0 || head.y < 0 || head.x >= tileCount || head.y >= tileCount) {
      gameOver()
      return
    }
  } else {
    // 穿透模式 - 从对面出现
    if (head.x < 0) head.x = tileCount - 1
    if (head.y < 0) head.y = tileCount - 1
    if (head.x >= tileCount) head.x = 0
    if (head.y >= tileCount) head.y = 0
  }

  // 检查是否撞到自己
  if (isSnakeCollision(head)) {
    gameOver()
    return
  }

  // 检查是否撞到障碍物
  for (let obs of obstacles) {
    if (head.x === obs.x && head.y === obs.y) {
      gameOver()
      return
    }
  }

  // 将新头部添加到蛇的起始位置
  snake.unshift(head)

  // 检查是否吃到食物
  if (head.x === food.x && head.y === food.y) {
    // 增加分数
    score += 10
    scoreElement.textContent = score

    // 检查成就
    checkAchievements()

    // 生成新食物
    generateFood()

    // 播放吃食物音效
    if (isSoundOn) {
      playSound('eat')
    }
  } else {
    // 如果没吃到食物,移除尾部
    snake.pop()
  }
}

// 检查蛇是否撞到自己
function isSnakeCollision(head) {
  for (let i = 1; i < snake.length; i++) {
    if (head.x === snake[i].x && head.y === snake[i].y) {
      return true
    }
  }
  return false
}

// 检查成就
function checkAchievements() {
  // 这里简化处理,实际应用中会有更复杂的成就系统
  if (score >= 100) {
    unlockAchievement('初出茅庐')
  }

  if (snake.length >= 50) {
    unlockAchievement('无限挑战')
  }
}

// 解锁成就
function unlockAchievement(name) {
  console.log(`成就已解锁: ${name}`)
  // 在实际应用中,这里会更新UI并播放成就解锁动画
}

// 游戏循环
function gameLoop() {
  if (!isPaused && !isGameOver) {
    moveSnake()
    draw()
  }
}

// 开始游戏
function startGame() {
  if (isGameOver) {
    initGame()
  }

  if (!gameInterval) {
    isPaused = false
    isGameOver = false
    gameInterval = setInterval(gameLoop, gameSpeed)
    document.getElementById('startBtn').innerHTML = '<i class="fas fa-play"></i> 重新开始'
  } else if (isPaused) {
    isPaused = false
    document.getElementById('pauseBtn').innerHTML = '<i class="fas fa-pause"></i> 暂停'
  }
}

// 暂停游戏
function pauseGame() {
  if (!isGameOver && gameInterval) {
    isPaused = !isPaused
    document.getElementById('pauseBtn').innerHTML = isPaused ? '<i class="fas fa-play"></i> 继续' : '<i class="fas fa-pause"></i> 暂停'
  }
}

// 游戏结束
function gameOver() {
  isGameOver = true
  clearInterval(gameInterval)
  clearInterval(timeInterval)
  gameInterval = null

  finalScoreElement.textContent = score
  gameOverElement.classList.add('show')

  // 播放游戏结束音效
  if (isSoundOn) {
    playSound('gameover')
  }

  // 更新排行榜
  updateLeaderboard('玩家', score)
}

// 播放音效
function playSound(type) {
  // 在实际应用中,这里会播放音频文件
  console.log(`Playing sound: ${type}`)
}

// 更新排行榜
function updateLeaderboard(name, score) {
  // 这里简化处理,实际应用中会保存到本地存储或服务器
  const leaderboard = document.getElementById('leaderboard')
  console.log(`Updating leaderboard with ${name}: ${score}`)
}

// 开始计时器
function startTimer() {
  clearInterval(timeInterval)
  gameTime = 0
  updateTimer()

  timeInterval = setInterval(() => {
    if (!isPaused && !isGameOver) {
      gameTime++
      updateTimer()
    }
  }, 1000)
}

// 更新计时器显示
function updateTimer() {
  const minutes = Math.floor(gameTime / 60)
  const seconds = gameTime % 60
  timeElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}

// 切换音效
function toggleSound() {
  isSoundOn = !isSoundOn
  document.getElementById('soundBtn').innerHTML = isSoundOn ? '<i class="fas fa-volume-up"></i> 音效: 开' : '<i class="fas fa-volume-mute"></i> 音效: 关'
}

// 保存设置
function saveSettings() {
  const settings = {
    speed: document.getElementById('gameSpeed').value,
    gridSize: document.getElementById('gridSize').value,
    wallMode: document.getElementById('wallMode').value,
    sound: isSoundOn
  }

  localStorage.setItem('snakeGameSettings', JSON.stringify(settings))
  alert('设置已保存!')
}

// 加载设置
function loadSettings() {
  const savedSettings = localStorage.getItem('snakeGameSettings')
  if (savedSettings) {
    const settings = JSON.parse(savedSettings)
    document.getElementById('gameSpeed').value = settings.speed
    document.getElementById('speedValue').textContent = settings.speed
    speedElement.textContent = settings.speed
    document.getElementById('gridSize').value = settings.gridSize
    document.getElementById('wallMode').value = settings.wallMode
    isSoundOn = settings.sound

    // 更新音效按钮状态
    document.getElementById('soundBtn').innerHTML = isSoundOn ? '<i class="fas fa-volume-up"></i> 音效: 开' : '<i class="fas fa-volume-mute"></i> 音效: 关'

    // 更新游戏速度
    gameSpeed = 210 - settings.speed * 10
  }
}

// 重置设置
function resetSettings() {
  localStorage.removeItem('snakeGameSettings')
  document.getElementById('gameSpeed').value = 5
  document.getElementById('speedValue').textContent = 5
  speedElement.textContent = 5
  document.getElementById('gridSize').value = 20
  document.getElementById('wallMode').value = 'solid'
  isSoundOn = true

  document.getElementById('soundBtn').innerHTML = '<i class="fas fa-volume-up"></i> 音效: 开'
  gameSpeed = 160

  alert('设置已重置为默认值!')
}

// 切换标签页
function switchTab(tabName) {
  // 隐藏所有标签页
  document.querySelectorAll('.tab-content').forEach(tab => {
    tab.classList.remove('active')
  })

  // 取消所有标签的激活状态
  document.querySelectorAll('.tab').forEach(tab => {
    tab.classList.remove('active')
  })

  // 激活选中的标签页
  document.getElementById(`${tabName}Tab`).classList.add('active')

  // 激活选中的标签
  document.querySelector(`.tab[data-tab="${tabName}"]`).classList.add('active')

  // 根据标签页显示/隐藏编辑器
  if (tabName === 'level-editor') {
    document.getElementById('levelEditor').style.display = 'block'
    isEditing = true
  } else {
    document.getElementById('levelEditor').style.display = 'none'
    isEditing = false
  }

  // 根据标签页显示/隐藏多人游戏状态
  if (tabName === 'multiplayer') {
    document.getElementById('multiplayerStatus').style.display = 'flex'
    isMultiplayer = true
  } else {
    document.getElementById('multiplayerStatus').style.display = 'none'
    isMultiplayer = false
  }
}

// 初始化事件监听
function initEvents() {
  // 键盘控制
  document.addEventListener('keydown', e => {
    // 防止按键滚动页面
    if (e.key.startsWith('Arrow')) {
      e.preventDefault()
    }

    // 根据按键改变方向(防止180度转向)
    switch (e.key) {
      case 'ArrowUp':
        if (dy === 0) {
          dx = 0
          dy = -1
        }
        break
      case 'ArrowDown':
        if (dy === 0) {
          dx = 0
          dy = 1
        }
        break
      case 'ArrowLeft':
        if (dx === 0) {
          dx = -1
          dy = 0
        }
        break
      case 'ArrowRight':
        if (dx === 0) {
          dx = 1
          dy = 0
        }
        break
      case ' ':
        pauseGame()
        break
    }
  })

  // 标签切换事件
  document.querySelectorAll('.tab').forEach(tab => {
    tab.addEventListener('click', () => {
      switchTab(tab.dataset.tab)
    })
  })

  // 按钮事件
  document.getElementById('startBtn').addEventListener('click', startGame)
  document.getElementById('pauseBtn').addEventListener('click', pauseGame)
  document.getElementById('restartBtn').addEventListener('click', startGame)
  document.getElementById('soundBtn').addEventListener('click', toggleSound)
  document.getElementById('saveBtn').addEventListener('click', saveSettings)
  document.getElementById('resetSettings').addEventListener('click', resetSettings)
  document.getElementById('createLobby').addEventListener('click', initMultiplayerGame)

  // 移动端控制按钮
  document.getElementById('upBtn').addEventListener('click', () => {
    if (dy === 0) {
      dx = 0
      dy = -1
    }
  })

  document.getElementById('downBtn').addEventListener('click', () => {
    if (dy === 0) {
      dx = 0
      dy = 1
    }
  })

  document.getElementById('leftBtn').addEventListener('click', () => {
    if (dx === 0) {
      dx = -1
      dy = 0
    }
  })

  document.getElementById('rightBtn').addEventListener('click', () => {
    if (dx === 0) {
      dx = 1
      dy = 0
    }
  })

  // 速度滑块事件
  document.getElementById('gameSpeed').addEventListener('input', e => {
    const speedValue = e.target.value
    document.getElementById('speedValue').textContent = speedValue
    speedElement.textContent = speedValue
    gameSpeed = 210 - speedValue * 10

    if (gameInterval) {
      clearInterval(gameInterval)
      gameInterval = setInterval(gameLoop, gameSpeed)
    }
  })

  // 网格大小改变事件
  document.getElementById('gridSize').addEventListener('change', e => {
    gridSize = parseInt(e.target.value)
    tileCount = canvas.width / gridSize
    initGame()
  })

  // 上传功能
  document.getElementById('uploadBg').addEventListener('click', () => {
    document.getElementById('bgUpload').click()
  })

  document.getElementById('uploadSkin').addEventListener('click', () => {
    document.getElementById('skinUpload').click()
  })

  document.getElementById('bgUpload').addEventListener('change', handleBackgroundUpload)
  document.getElementById('skinUpload').addEventListener('change', handleSkinUpload)

  // 编辑器工具选择
  document.getElementById('wallTool').addEventListener('click', () => {
    currentTool = 'wall'
  })

  document.getElementById('obstacleTool').addEventListener('click', () => {
    currentTool = 'obstacle'
  })

  document.getElementById('eraseTool').addEventListener('click', () => {
    currentTool = 'erase'
  })

  // 画布点击事件(用于关卡编辑器)
  canvas.addEventListener('click', e => {
    if (!isEditing) return

    const rect = canvas.getBoundingClientRect()
    const x = e.clientX - rect.left
    const y = e.clientY - rect.top

    const gridX = Math.floor(x / gridSize)
    const gridY = Math.floor(y / gridSize)

    if (currentTool === 'wall') {
      // 添加墙壁
      obstacles.push({ x: gridX, y: gridY })
    } else if (currentTool === 'obstacle') {
      // 添加障碍物
      obstacles.push({ x: gridX, y: gridY })
    } else if (currentTool === 'erase') {
      // 删除墙壁或障碍物
      obstacles = obstacles.filter(obs => !(obs.x === gridX && obs.y === gridY))
    }

    draw()
  })
}

// 处理背景上传
function handleBackgroundUpload(e) {
  const file = e.target.files[0]
  if (file) {
    const reader = new FileReader()
    reader.onload = function(event) {
      // 创建背景图像
      const bgImage = new Image()
      bgImage.onload = function() {
        // 应用背景
        ctx.drawImage(bgImage, 0, 0, canvas.width, canvas.height)
      }
      bgImage.src = event.target.result
    }
    reader.readAsDataURL(file)
  }
}

// 处理皮肤上传
function handleSkinUpload(e) {
  const file = e.target.files[0]
  if (file) {
    const reader = new FileReader()
    reader.onload = function(event) {
      // 在实际应用中,这里会设置蛇的皮肤
      console.log('Skin uploaded:', file.name)
      alert(`蛇皮肤 "${file.name}" 上传成功!`)
    }
    reader.readAsDataURL(file)
  }
}

// 初始化游戏
function init() {
  loadSettings()
  initEvents()
  initGame()
}

// 启动游戏
window.onload = init

七、性能优化策略

  1. Canvas渲染优化:使用离屏渲染和局部重绘技术
  2. 游戏循环控制:基于requestAnimationFrame的自适应帧率
  3. 内存管理:及时释放不再使用的资源
  4. 数据序列化:高效的游戏状态保存与加载

这个增强版贪吃蛇游戏展示了如何通过现代Web技术赋予经典游戏新的生命力。它不仅保留了原始游戏的简单乐趣,还通过多人模式、成就系统和关卡编辑器等现代游戏元素,创造了深度和广度都大大扩展的游戏体验。
这种开发模式证明了即使是最简单的游戏概念,也可以通过技术创新和用户体验优化,发展成为吸引现代玩家的复杂产品。对于开发者而言,这个项目展示了如何平衡传统与创新,在保留经典魅力的同时引入现代功能。
最终,这个贪吃蛇游戏的进化之旅提醒我们,优秀的游戏设计不仅仅是关于尖端技术或复杂机制,而是关于创造引人入胜的体验,让玩家愿意一次又一次地回来享受游戏的乐趣。


网站公告

今日签到

点亮在社区的每一天
去签到