weyhao 发表于 2025-9-23 10:59:45

ESP32-C5——断网可玩的局域网2048游戏

在某些特殊的场合之下,比如没有网络的大兴安岭,克拉玛利,比如不允许上网的某些研究所,比如在飞机上。那么我们如何连接热点,上网连线一款游戏解闷呢?前些天本人收到了dfrobot寄来的Firebbetle Esp32-C5试用板,心想刚好可以利用其自带的wifi以及http功能,将其作为微型服务器,利用Ap模式发出局域网热点信号,连接热点访问其中的小游戏。

废话不说,先上效果

目前只需要连接ESP32的wifi热点,以及输入密码12345678就可以啦。下面有四个方向箭,点击就可以实现对于2048小游戏的控制。得益于esp32c5的优越性能,目前游玩过程很流畅,也很顺利。如果有多人接入,只需要避免同时一次性大量访问就好。
视频演示

当然由于是试用版的缘故,以及科学上网变得更加困难,折腾了一段时间,开发板具体的使用方法是,下载arduino2.3.6,将
附件当中的json文件保存到下面的文件夹下,注意将原来的package_index.json删除,将这个json重命名为package_index.json。注意arduino当中文件-首选项-其余开发板链接当中的链接全部删除,然后再打开arduino,选择esp32 espress的下面的3.3.0-alpha-cn进行开发

arduino源代码展示如下#include <WiFi.h>
#include <WebServer.h>

/* Put your SSID & Password */
const char* ssid   = "ESP32";   // Enter SSID here
const char* password = "12345678";// Enter Password here

/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);

WebServer server(80);

void setup()
{
    Serial.begin(115200);

    WiFi.softAP(ssid, password);
    WiFi.softAPConfig(local_ip, gateway, subnet);
    delay(100);

    server.on("/", handle_on_connect);
    server.onNotFound(handle_not_found);

    server.begin();
    Serial.println("HTTP server started");
}

void loop()
{
    server.handleClient();
}

void handle_on_connect()
{
    Serial.println("Client connected");
    server.send(200, "text/html", send_2048_html());
}

void handle_not_found()
{
    server.send(404, "text/plain", "Not found");
}

String send_2048_html()
{
    String ptr = "<!DOCTYPE html>\n";
    ptr += "<html lang='zh'>\n";
    ptr += "<head>\n";
    ptr += "<meta charset='UTF-8'>\n";
    ptr += "<meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=no'>\n";
    ptr += "<title>ESP32 2048游戏</title>\n";
    ptr += "<style>\n";
    ptr += "    body {\n";
    ptr += "      font-family: Arial, sans-serif;\n";
    ptr += "      text-align: center;\n";
    ptr += "      background-color: #faf8ef;\n";
    ptr += "      margin: 0;\n";
    ptr += "      padding: 20px;\n";
    ptr += "    }\n";
    ptr += "    h1 {\n";
    ptr += "      color: #776e65;\n";
    ptr += "      font-size: 28px;\n";
    ptr += "      margin-bottom: 10px;\n";
    ptr += "    }\n";
    ptr += "    .game-container {\n";
    ptr += "      display: flex;\n";
    ptr += "      flex-direction: column;\n";
    ptr += "      align-items: center;\n";
    ptr += "      margin-top: 20px;\n";
    ptr += "    }\n";
    ptr += "    .game-header {\n";
    ptr += "      display: flex;\n";
    ptr += "      justify-content: space-between;\n";
    ptr += "      width: 300px;\n";
    ptr += "      margin-bottom: 20px;\n";
    ptr += "    }\n";
    ptr += "    .score-container {\n";
    ptr += "      background: #bbada0;\n";
    ptr += "      padding: 10px 15px;\n";
    ptr += "      border-radius: 5px;\n";
    ptr += "      color: white;\n";
    ptr += "      font-weight: bold;\n";
    ptr += "      text-align: center;\n";
    ptr += "      min-width: 80px;\n";
    ptr += "    }\n";
    ptr += "    .score-title {\n";
    ptr += "      font-size: 14px;\n";
    ptr += "      color: #eee4da;\n";
    ptr += "    }\n";
    ptr += "    .score-value {\n";
    ptr += "      font-size: 20px;\n";
    ptr += "    }\n";
    ptr += "    .grid-container {\n";
    ptr += "      background-color: #bbada0;\n";
    ptr += "      border-radius: 6px;\n";
    ptr += "      width: 300px;\n";
    ptr += "      height: 300px;\n";
    ptr += "      padding: 10px;\n";
    ptr += "      position: relative;\n";
    ptr += "      box-sizing: border-box;\n";
    ptr += "    }\n";
    ptr += "    .grid-row {\n";
    ptr += "      display: flex;\n";
    ptr += "      margin-bottom: 10px;\n";
    ptr += "      height: 65px;\n";
    ptr += "    }\n";
    ptr += "    .grid-row:last-child {\n";
    ptr += "      margin-bottom: 0;\n";
    ptr += "    }\n";
    ptr += "    .grid-cell {\n";
    ptr += "      width: 65px;\n";
    ptr += "      height: 65px;\n";
    ptr += "      margin-right: 10px;\n";
    ptr += "      background-color: #cdc1b4;\n";
    ptr += "      border-radius: 3px;\n";
    ptr += "      display: flex;\n";
    ptr += "      justify-content: center;\n";
    ptr += "      align-items: center;\n";
    ptr += "      font-size: 24px;\n";
    ptr += "      font-weight: bold;\n";
    ptr += "      color: #776e65;\n";
    ptr += "    }\n";
    ptr += "    .grid-cell:last-child {\n";
    ptr += "      margin-right: 0;\n";
    ptr += "    }\n";
    ptr += "    .tile-2 { background-color: #eee4da; }\n";
    ptr += "    .tile-4 { background-color: #ede0c8; }\n";
    ptr += "    .tile-8 { background-color: #f2b179; color: #f9f6f2; }\n";
    ptr += "    .tile-16 { background-color: #f59563; color: #f9f6f2; }\n";
    ptr += "    .tile-32 { background-color: #f67c5f; color: #f9f6f2; }\n";
    ptr += "    .tile-64 { background-color: #f65e3b; color: #f9f6f2; }\n";
    ptr += "    .tile-128 { background-color: #edcf72; color: #f9f6f2; font-size: 20px; }\n";
    ptr += "    .tile-256 { background-color: #edcc61; color: #f9f6f2; font-size: 20px; }\n";
    ptr += "    .tile-512 { background-color: #edc850; color: #f9f6f2; font-size: 20px; }\n";
    ptr += "    .tile-1024 { background-color: #edc53f; color: #f9f6f2; font-size: 16px; }\n";
    ptr += "    .tile-2048 { background-color: #edc22e; color: #f9f6f2; font-size: 16px; }\n";
    ptr += "    .controls {\n";
    ptr += "      margin-top: 20px;\n";
    ptr += "    }\n";
    ptr += "    .btn {\n";
    ptr += "      background-color: #8f7a66;\n";
    ptr += "      color: white;\n";
    ptr += "      border: none;\n";
    ptr += "      border-radius: 5px;\n";
    ptr += "      padding: 10px 20px;\n";
    ptr += "      font-weight: bold;\n";
    ptr += "      cursor: pointer;\n";
    ptr += "      margin: 5px;\n";
    ptr += "    }\n";
    ptr += "    .btn:hover {\n";
    ptr += "      background-color: #7c6957;\n";
    ptr += "    }\n";
    ptr += "    .game-message {\n";
    ptr += "      display: none;\n";
    ptr += "      position: absolute;\n";
    ptr += "      top: 0;\n";
    ptr += "      left: 0;\n";
    ptr += "      right: 0;\n";
    ptr += "      bottom: 0;\n";
    ptr += "      background: rgba(238, 228, 218, 0.73);\n";
    ptr += "      z-index: 100;\n";
    ptr += "      flex-direction: column;\n";
    ptr += "      align-items: center;\n";
    ptr += "      justify-content: center;\n";
    ptr += "      border-radius: 6px;\n";
    ptr += "      color: #776e65;\n";
    ptr += "      font-weight: bold;\n";
    ptr += "      font-size: 30px;\n";
    ptr += "    }\n";
    ptr += "    .game-message.game-won {\n";
    ptr += "      background: rgba(237, 194, 46, 0.5);\n";
    ptr += "      color: #f9f6f2;\n";
    ptr += "    }\n";
    ptr += "    .game-message p {\n";
    ptr += "      margin: 0;\n";
    ptr += "      margin-bottom: 20px;\n";
    ptr += "    }\n";
    ptr += "    .swipe-controls {\n";
    ptr += "      display: flex;\n";
    ptr += "      flex-wrap: wrap;\n";
    ptr += "      justify-content: center;\n";
    ptr += "      margin-top: 20px;\n";
    ptr += "    }\n";
    ptr += "    .swipe-btn {\n";
    ptr += "      width: 80px;\n";
    ptr += "      height: 80px;\n";
    ptr += "      margin: 5px;\n";
    ptr += "      font-size: 30px;\n";
    ptr += "      background-color: #bbada0;\n";
    ptr += "      color: white;\n";
    ptr += "      border: none;\n";
    ptr += "      border-radius: 5px;\n";
    ptr += "      display: flex;\n";
    ptr += "      justify-content: center;\n";
    ptr += "      align-items: center;\n";
    ptr += "      cursor: pointer;\n";
    ptr += "    }\n";
    ptr += "    .swipe-btn:active {\n";
    ptr += "      background-color: #8f7a66;\n";
    ptr += "    }\n";
    ptr += "    .footer {\n";
    ptr += "      margin-top: 30px;\n";
    ptr += "      font-size: 14px;\n";
    ptr += "      color: #776e65;\n";
    ptr += "    }\n";
    ptr += "</style>\n";
    ptr += "</head>\n";
    ptr += "<body>\n";
    ptr += "<h1>ESP32 2048游戏</h1>\n";
    ptr += "<div class='game-container'>\n";
    ptr += "    <div class='game-header'>\n";
    ptr += "      <div class='score-container'>\n";
    ptr += "      <div class='score-title'>分数</div>\n";
    ptr += "      <div id='score' class='score-value'>0</div>\n";
    ptr += "      </div>\n";
    ptr += "      <div class='score-container'>\n";
    ptr += "      <div class='score-title'>最高分</div>\n";
    ptr += "      <div id='best-score' class='score-value'>0</div>\n";
    ptr += "      </div>\n";
    ptr += "    </div>\n";
    ptr += "    <div class='grid-container'>\n";
    ptr += "      <div id='game-message' class='game-message'>\n";
    ptr += "      <p></p>\n";
    ptr += "      <button id='retry-btn' class='btn'>再试一次</button>\n";
    ptr += "      </div>\n";
    ptr += "      <div class='grid-row'>\n";
    ptr += "      <div id='cell-0-0' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-0-1' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-0-2' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-0-3' class='grid-cell'></div>\n";
    ptr += "      </div>\n";
    ptr += "      <div class='grid-row'>\n";
    ptr += "      <div id='cell-1-0' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-1-1' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-1-2' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-1-3' class='grid-cell'></div>\n";
    ptr += "      </div>\n";
    ptr += "      <div class='grid-row'>\n";
    ptr += "      <div id='cell-2-0' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-2-1' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-2-2' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-2-3' class='grid-cell'></div>\n";
    ptr += "      </div>\n";
    ptr += "      <div class='grid-row'>\n";
    ptr += "      <div id='cell-3-0' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-3-1' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-3-2' class='grid-cell'></div>\n";
    ptr += "      <div id='cell-3-3' class='grid-cell'></div>\n";
    ptr += "      </div>\n";
    ptr += "    </div>\n";
    ptr += "    <div class='controls'>\n";
    ptr += "      <button id='new-game-btn' class='btn'>新游戏</button>\n";
    ptr += "    </div>\n";
    ptr += "    <div class='swipe-controls'>\n";
    ptr += "      <div style='width: 90px; height: 90px;'></div>\n";
    ptr += "      <button id='up-btn' class='swipe-btn'>↑</button>\n";
    ptr += "      <div style='width: 90px; height: 90px;'></div>\n";
    ptr += "      <button id='left-btn' class='swipe-btn'>←</button>\n";
    ptr += "      <div style='width: 90px; height: 90px;'></div>\n";
    ptr += "      <button id='right-btn' class='swipe-btn'>→</button>\n";
    ptr += "      <div style='width: 90px; height: 90px;'></div>\n";
    ptr += "      <button id='down-btn' class='swipe-btn'>↓</button>\n";
    ptr += "      <div style='width: 90px; height: 90px;'></div>\n";
    ptr += "    </div>\n";
    ptr += "</div>\n";
    ptr += "<div class='footer'>\n";
    ptr += "    <p>ESP32网页2048游戏 - 基于ESP32 Web Server</p>\n";
    ptr += "</div>\n";
   
    // 添加JavaScript代码
    ptr += "<script>\n";
    ptr += "    // 游戏状态变量\n";
    ptr += "    let grid = [\n";
    ptr += "      ,\n";
    ptr += "      ,\n";
    ptr += "      ,\n";
    ptr += "      \n";
    ptr += "    ];\n";
    ptr += "    let score = 0;\n";
    ptr += "    let bestScore = 0;\n";
    ptr += "    let gameOver = false;\n";
    ptr += "    let gameWon = false;\n";
   
    ptr += "    // DOM元素\n";
    ptr += "    const scoreElement = document.getElementById('score');\n";
    ptr += "    const bestScoreElement = document.getElementById('best-score');\n";
    ptr += "    const gameMessageElement = document.getElementById('game-message');\n";
    ptr += "    const newGameBtn = document.getElementById('new-game-btn');\n";
    ptr += "    const retryBtn = document.getElementById('retry-btn');\n";
    ptr += "    const upBtn = document.getElementById('up-btn');\n";
    ptr += "    const leftBtn = document.getElementById('left-btn');\n";
    ptr += "    const rightBtn = document.getElementById('right-btn');\n";
    ptr += "    const downBtn = document.getElementById('down-btn');\n";
   
    ptr += "    // 初始化游戏\n";
    ptr += "    function initGame() {\n";
    ptr += "      grid = [\n";
    ptr += "      ,\n";
    ptr += "      ,\n";
    ptr += "      ,\n";
    ptr += "      \n";
    ptr += "      ];\n";
    ptr += "      score = 0;\n";
    ptr += "      gameOver = false;\n";
    ptr += "      gameWon = false;\n";
    ptr += "      scoreElement.textContent = '0';\n";
    ptr += "      gameMessageElement.style.display = 'none';\n";
    ptr += "      \n";
    ptr += "      // 添加两个初始方块\n";
    ptr += "      addRandomTile();\n";
    ptr += "      addRandomTile();\n";
    ptr += "      \n";
    ptr += "      updateGrid();\n";
    ptr += "    }\n";
   
    ptr += "    // 更新网格显示\n";
    ptr += "    function updateGrid() {\n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "          const cell = document.getElementById(`cell-${row}-${col}`);\n";
    ptr += "          const value = grid;\n";
    ptr += "          \n";
    ptr += "          // 清除所有类\n";
    ptr += "          cell.className = 'grid-cell';\n";
    ptr += "          cell.textContent = '';\n";
    ptr += "          \n";
    ptr += "          if (value !== 0) {\n";
    ptr += "            cell.textContent = value;\n";
    ptr += "            cell.classList.add(`tile-${value}`);\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "    }\n";
   
    ptr += "    // 添加随机方块\n";
    ptr += "    function addRandomTile() {\n";
    ptr += "      const emptyCells = [];\n";
    ptr += "      \n";
    ptr += "      // 找出所有空单元格\n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "          if (grid === 0) {\n";
    ptr += "            emptyCells.push({ row, col });\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 如果有空单元格,随机选择一个并添加2或4\n";
    ptr += "      if (emptyCells.length > 0) {\n";
    ptr += "      const randomCell = emptyCells;\n";
    ptr += "      grid = Math.random() < 0.9 ? 2 : 4;\n";
    ptr += "      }\n";
    ptr += "    }\n";
   
    ptr += "    // 检查游戏是否结束\n";
    ptr += "    function checkGameOver() {\n";
    ptr += "      // 检查是否有空单元格\n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "          if (grid === 0) {\n";
    ptr += "            return false;\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 检查是否有可合并的相邻单元格\n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "          const value = grid;\n";
    ptr += "          \n";
    ptr += "          // 检查右侧\n";
    ptr += "          if (col < 3 && grid === value) {\n";
    ptr += "            return false;\n";
    ptr += "          }\n";
    ptr += "          \n";
    ptr += "          // 检查下方\n";
    ptr += "          if (row < 3 && grid === value) {\n";
    ptr += "            return false;\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      return true;\n";
    ptr += "    }\n";
   
    ptr += "    // 检查是否获胜(达到2048)\n";
    ptr += "    function checkWin() {\n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "          if (grid === 2048) {\n";
    ptr += "            return true;\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      return false;\n";
    ptr += "    }\n";
   
    ptr += "    // 更新分数\n";
    ptr += "    function updateScore(points) {\n";
    ptr += "      score += points;\n";
    ptr += "      scoreElement.textContent = score;\n";
    ptr += "      \n";
    ptr += "      if (score > bestScore) {\n";
    ptr += "      bestScore = score;\n";
    ptr += "      bestScoreElement.textContent = bestScore;\n";
    ptr += "      localStorage.setItem('bestScore', bestScore);\n";
    ptr += "      }\n";
    ptr += "    }\n";
   
    ptr += "    // 显示游戏结束或胜利消息\n";
    ptr += "    function showGameMessage(won) {\n";
    ptr += "      gameMessageElement.style.display = 'flex';\n";
    ptr += "      gameMessageElement.querySelector('p').textContent = won ? '你赢了!' : '游戏结束!';\n";
    ptr += "      if (won) {\n";
    ptr += "      gameMessageElement.classList.add('game-won');\n";
    ptr += "      } else {\n";
    ptr += "      gameMessageElement.classList.remove('game-won');\n";
    ptr += "      }\n";
    ptr += "    }\n";
   
    ptr += "    // 移动方向处理函数\n";
    ptr += "    function move(direction) {\n";
    ptr += "      if (gameOver || gameWon) return;\n";
    ptr += "      \n";
    ptr += "      let moved = false;\n";
    ptr += "      \n";
    ptr += "      // 创建网格副本用于比较\n";
    ptr += "      const previousGrid = JSON.parse(JSON.stringify(grid));\n";
    ptr += "      \n";
    ptr += "      // 根据方向执行移动\n";
    ptr += "      switch (direction) {\n";
    ptr += "      case 'up':\n";
    ptr += "          moved = moveUp();\n";
    ptr += "          break;\n";
    ptr += "      case 'right':\n";
    ptr += "          moved = moveRight();\n";
    ptr += "          break;\n";
    ptr += "      case 'down':\n";
    ptr += "          moved = moveDown();\n";
    ptr += "          break;\n";
    ptr += "      case 'left':\n";
    ptr += "          moved = moveLeft();\n";
    ptr += "          break;\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 如果有移动,添加新方块并更新网格\n";
    ptr += "      if (moved) {\n";
    ptr += "      addRandomTile();\n";
    ptr += "      updateGrid();\n";
    ptr += "      \n";
    ptr += "      // 检查是否获胜\n";
    ptr += "      if (checkWin()) {\n";
    ptr += "          gameWon = true;\n";
    ptr += "          showGameMessage(true);\n";
    ptr += "      }\n";
    ptr += "      // 检查是否游戏结束\n";
    ptr += "      else if (checkGameOver()) {\n";
    ptr += "          gameOver = true;\n";
    ptr += "          showGameMessage(false);\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "    }\n";
   
    ptr += "    // 向上移动\n";
    ptr += "    function moveUp() {\n";
    ptr += "      let moved = false;\n";
    ptr += "      \n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "      // 合并相同的数字\n";
    ptr += "      for (let row = 0; row < 3; row++) {\n";
    ptr += "          if (grid !== 0) {\n";
    ptr += "            for (let nextRow = row + 1; nextRow < 4; nextRow++) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                if (grid === grid) {\n";
    ptr += "                  grid *= 2;\n";
    ptr += "                  grid = 0;\n";
    ptr += "                  updateScore(grid);\n";
    ptr += "                  moved = true;\n";
    ptr += "                }\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 移动所有方块\n";
    ptr += "      for (let row = 0; row < 3; row++) {\n";
    ptr += "          if (grid === 0) {\n";
    ptr += "            for (let nextRow = row + 1; nextRow < 4; nextRow++) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                grid = grid;\n";
    ptr += "                grid = 0;\n";
    ptr += "                moved = true;\n";
    ptr += "                row--; // 重新检查当前行\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      return moved;\n";
    ptr += "    }\n";
   
    ptr += "    // 向右移动\n";
    ptr += "    function moveRight() {\n";
    ptr += "      let moved = false;\n";
    ptr += "      \n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      // 合并相同的数字\n";
    ptr += "      for (let col = 3; col > 0; col--) {\n";
    ptr += "          if (grid !== 0) {\n";
    ptr += "            for (let prevCol = col - 1; prevCol >= 0; prevCol--) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                if (grid === grid) {\n";
    ptr += "                  grid *= 2;\n";
    ptr += "                  grid = 0;\n";
    ptr += "                  updateScore(grid);\n";
    ptr += "                  moved = true;\n";
    ptr += "                }\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 移动所有方块\n";
    ptr += "      for (let col = 3; col > 0; col--) {\n";
    ptr += "          if (grid === 0) {\n";
    ptr += "            for (let prevCol = col - 1; prevCol >= 0; prevCol--) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                grid = grid;\n";
    ptr += "                grid = 0;\n";
    ptr += "                moved = true;\n";
    ptr += "                col++; // 重新检查当前列\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      return moved;\n";
    ptr += "    }\n";
   
    ptr += "    // 向下移动\n";
    ptr += "    function moveDown() {\n";
    ptr += "      let moved = false;\n";
    ptr += "      \n";
    ptr += "      for (let col = 0; col < 4; col++) {\n";
    ptr += "      // 合并相同的数字\n";
    ptr += "      for (let row = 3; row > 0; row--) {\n";
    ptr += "          if (grid !== 0) {\n";
    ptr += "            for (let prevRow = row - 1; prevRow >= 0; prevRow--) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                if (grid === grid) {\n";
    ptr += "                  grid *= 2;\n";
    ptr += "                  grid = 0;\n";
    ptr += "                  updateScore(grid);\n";
    ptr += "                  moved = true;\n";
    ptr += "                }\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 移动所有方块\n";
    ptr += "      for (let row = 3; row > 0; row--) {\n";
    ptr += "          if (grid === 0) {\n";
    ptr += "            for (let prevRow = row - 1; prevRow >= 0; prevRow--) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                grid = grid;\n";
    ptr += "                grid = 0;\n";
    ptr += "                moved = true;\n";
    ptr += "                row++; // 重新检查当前行\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      return moved;\n";
    ptr += "    }\n";
   
    ptr += "    // 向左移动\n";
    ptr += "    function moveLeft() {\n";
    ptr += "      let moved = false;\n";
    ptr += "      \n";
    ptr += "      for (let row = 0; row < 4; row++) {\n";
    ptr += "      // 合并相同的数字\n";
    ptr += "      for (let col = 0; col < 3; col++) {\n";
    ptr += "          if (grid !== 0) {\n";
    ptr += "            for (let nextCol = col + 1; nextCol < 4; nextCol++) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                if (grid === grid) {\n";
    ptr += "                  grid *= 2;\n";
    ptr += "                  grid = 0;\n";
    ptr += "                  updateScore(grid);\n";
    ptr += "                  moved = true;\n";
    ptr += "                }\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      // 移动所有方块\n";
    ptr += "      for (let col = 0; col < 3; col++) {\n";
    ptr += "          if (grid === 0) {\n";
    ptr += "            for (let nextCol = col + 1; nextCol < 4; nextCol++) {\n";
    ptr += "            if (grid !== 0) {\n";
    ptr += "                grid = grid;\n";
    ptr += "                grid = 0;\n";
    ptr += "                moved = true;\n";
    ptr += "                col--; // 重新检查当前列\n";
    ptr += "                break;\n";
    ptr += "            }\n";
    ptr += "            }\n";
    ptr += "          }\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "      \n";
    ptr += "      return moved;\n";
    ptr += "    }\n";
   
    // 修复事件***和初始化代码
    ptr += "    // 加载最高分\n";
    ptr += "    function loadBestScore() {\n";
    ptr += "      const savedBestScore = localStorage.getItem('bestScore');\n";
    ptr += "      if (savedBestScore) {\n";
    ptr += "      bestScore = parseInt(savedBestScore);\n";
    ptr += "      bestScoreElement.textContent = bestScore;\n";
    ptr += "      }\n";
    ptr += "    }\n";
   
    ptr += "    // 事件***\n";
    ptr += "    newGameBtn.addEventListener('click', initGame);\n";
    ptr += "    retryBtn.addEventListener('click', initGame);\n";
    ptr += "    upBtn.addEventListener('click', () => move('up'));\n";
    ptr += "    rightBtn.addEventListener('click', () => move('right'));\n";
    ptr += "    downBtn.addEventListener('click', () => move('down'));\n";
    ptr += "    leftBtn.addEventListener('click', () => move('left'));\n";
   
    ptr += "    // 键盘控制\n";
    ptr += "    document.addEventListener('keydown', (e) => {\n";
    ptr += "      if (gameOver || gameWon) return;\n";
    ptr += "      \n";
    ptr += "      switch (e.key) {\n";
    ptr += "      case 'ArrowUp':\n";
    ptr += "          move('up');\n";
    ptr += "          break;\n";
    ptr += "      case 'ArrowRight':\n";
    ptr += "          move('right');\n";
    ptr += "          break;\n";
    ptr += "      case 'ArrowDown':\n";
    ptr += "          move('down');\n";
    ptr += "          break;\n";
    ptr += "      case 'ArrowLeft':\n";
    ptr += "          move('left');\n";
    ptr += "          break;\n";
    ptr += "      }\n";
    ptr += "    });\n";
   
    ptr += "    // 触摸控制\n";
    ptr += "    let touchStartX = 0;\n";
    ptr += "    let touchStartY = 0;\n";
    ptr += "    let touchEndX = 0;\n";
    ptr += "    let touchEndY = 0;\n";
   
    ptr += "    document.addEventListener('touchstart', (e) => {\n";
    ptr += "      touchStartX = e.touches.clientX;\n";
    ptr += "      touchStartY = e.touches.clientY;\n";
    ptr += "    }, false);\n";
   
    ptr += "    document.addEventListener('touchend', (e) => {\n";
    ptr += "      if (gameOver || gameWon) return;\n";
    ptr += "      \n";
    ptr += "      touchEndX = e.changedTouches.clientX;\n";
    ptr += "      touchEndY = e.changedTouches.clientY;\n";
    ptr += "      \n";
    ptr += "      const deltaX = touchEndX - touchStartX;\n";
    ptr += "      const deltaY = touchEndY - touchStartY;\n";
    ptr += "      \n";
    ptr += "      // 确定滑动方向\n";
    ptr += "      if (Math.abs(deltaX) > Math.abs(deltaY)) {\n";
    ptr += "      // 水平滑动\n";
    ptr += "      if (deltaX > 20) {\n";
    ptr += "          move('right');\n";
    ptr += "      } else if (deltaX < -20) {\n";
    ptr += "          move('left');\n";
    ptr += "      }\n";
    ptr += "      } else {\n";
    ptr += "      // 垂直滑动\n";
    ptr += "      if (deltaY > 20) {\n";
    ptr += "          move('down');\n";
    ptr += "      } else if (deltaY < -20) {\n";
    ptr += "          move('up');\n";
    ptr += "      }\n";
    ptr += "      }\n";
    ptr += "    }, false);\n";
   
    ptr += "    // 阻止页面滚动\n";
    ptr += "    document.addEventListener('touchmove', (e) => {\n";
    ptr += "      if (e.target.closest('.grid-container')) {\n";
    ptr += "      e.preventDefault();\n";
    ptr += "      }\n";
    ptr += "    }, { passive: false });\n";
   
    ptr += "    // 初始化\n";
    ptr += "    loadBestScore();\n";
    ptr += "    initGame();\n";
    ptr += "</script>\n";
    ptr += "</body>\n";
    ptr += "</html>\n";
   
    return ptr;
}
页: [1]
查看完整版本: ESP32-C5——断网可玩的局域网2048游戏