You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS Canvas瓦片地图编辑器多维数组存储瓦片ID被覆盖问题

Canvas瓦片地图编辑器数组数据丢失问题修复

问题现象

开发基于Canvas的瓦片地图编辑器时,用于存储瓦片ID的二维数组无法持久保存数据:每次触发瓦片保存逻辑,之前存储的所有瓦片ID都会被覆盖,仅保留最新一次操作的瓦片ID,无法导出完整的地图数据用于后续碰撞检测。

问题根因

原有saveIdexedTiledMap函数存在逻辑错误:每次函数执行时,都会通过双层循环遍历所有地图格子,把整个数组的所有位置重置为0,再给当前点击的单个格子赋值瓦片ID。相当于每次保存都先清空全部历史数据,自然无法保留之前绘制的瓦片记录。
除此之外原有逻辑还存在三个数据不一致隐患:

  • 右键删除瓦片时没有同步更新数组对应位置的值
  • 点击清空画布按钮时没有重置数组,会出现画布空白但数组还留存旧数据的问题
  • 计算格子行列时没有做整数取整,可能出现浮点数数组索引导致赋值异常

修复步骤

  • 数组初始化仅执行一次:不要在每次保存时重置全量数组,改为在编辑器初始化、画布加载完成时,一次性创建和地图尺寸匹配、初始值全为0的二维数组。
  • 保存逻辑仅更新当前操作格子:触发绘制/删除操作时,只修改鼠标当前位置对应格子的数组值,不再遍历重置整个数组。
  • 全操作同步数据:删除单个瓦片、清空全画布时同步更新数组数据,保证画布显示和存储的地图数据完全一致。
  • 索引做整数校验:计算格子行列时增加取整逻辑,避免浮点数索引导致的数组赋值错误。

修复后核心代码

1. 全局变量与初始化逻辑

// 语义化重命名地图存储数组,避免无意义的array命名
let tileMapData = [];
// 提前计算地图行列常量,避免重复计算
const TILE_SIZE = 32;
const mapCols = canvas.width / TILE_SIZE;
const mapRows = canvas.height / TILE_SIZE;

// 初始化空地图数组,仅在加载、清空、改尺寸时调用
function initTileMapArray() {
  tileMapData = [];
  for (let row = 0; row < mapRows; row++) {
    // 用fill快速创建全0的行数组
    tileMapData[row] = new Array(mapCols).fill(0);
  }
}

// 在原有showSpreadSheetImg函数末尾,网格绘制完成后调用一次初始化
// 追加在canvasMapGrids.draw()之后即可
initTileMapArray();

2. 修复后的瓦片数据更新函数

/**
 * 更新地图瓦片数据
 * @param {string} operateType 操作类型:draw=绘制瓦片 delete=删除瓦片
 */
function updateTileMapData(operateType = 'draw') {
  // 计算当前鼠标位置对应的格子行列,取整保证索引为整数
  const gridRow = Math.floor(mouseCanvasGrids.y / TILE_SIZE);
  const gridCol = Math.floor(mouseCanvasGrids.x / TILE_SIZE);

  // 仅更新当前操作的格子,不重置全量数据
  if (operateType === 'draw' && selectedTile.length > 0) {
    tileMapData[gridRow][gridCol] = selectedTile[0].index;
  } else if (operateType === 'delete') {
    tileMapData[gridRow][gridCol] = 0;
  }

  console.log(tileMapData);
}

3. 调整原有逻辑的调用位置

  • 左键绘制瓦片逻辑末尾,把原来的saveIdexedTiledMap()替换为updateTileMapData('draw')
  • 右键删除瓦片的deleteSelectedTile函数末尾,追加updateTileMapData('delete')
  • 清空画布按钮的点击事件中,清空画布重绘网格后,追加initTileMapArray()重置全量数据为0
// 清空画布逻辑修改示例
clearCanvas.addEventListener("click", () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  canvasMapGrids.draw();
  initTileMapArray(); // 同步重置地图数组
});

后续使用建议

  • 导出地图JSON时直接调用JSON.stringify(tileMapData)即可得到标准格式的地图数据,可直接用于游戏中的瓦片渲染、碰撞检测逻辑。
  • 如果后续支持自定义地图尺寸、瓦片尺寸,只需要在配置提交后重新计算mapCols、mapRows的值,再调用initTileMapArray()即可适配新尺寸。
  • 可以给数组增加本地存储逻辑,页面刷新时从localStorage读取已保存的tileMapData重绘画布,避免刷新丢失编辑内容。

内容的提问来源于stack exchange,提问作者DafrDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:15:35