JavaScript 2D数组瓦片地图Canvas滚动实现技术咨询
实现Canvas瓦片地图滚动(固定显示3x3区域)
这个需求的核心是反向滚动逻辑:我们不让玩家在Canvas里移动,而是让玩家始终固定在画布中心,通过调整地图的绘制偏移量,来营造玩家在地图中行走的视觉错觉。同时只绘制玩家周围的3x3瓦片,既保证性能,又严格符合你要的显示范围。
核心思路拆解
- 定义瓦片大小:800x800的Canvas要显示3x3瓦片,所以每个瓦片的尺寸是
800/3 ≈ 266.67px,刚好填满画布。 - 玩家位置用瓦片坐标表示(比如初始在地图的
(1,1)位置,对应tileMap里的空地)。 - 地图偏移量:通过计算偏移量,让玩家所在的瓦片始终处于Canvas中心,绘制地图时加上这个偏移量,就实现了地图滚动。
- 只绘制玩家周围3x3的瓦片:循环遍历
[玩家X-1, 玩家X+1]和[玩家Y-1, 玩家Y+1]的瓦片范围,避免绘制整个大地图。
完整实现代码
<canvas id='draw' width=800 height=800 style="border:1px solid #000;"></canvas> <script> // 1. 基础变量定义 const canvas = document.getElementById('draw'); const ctx = canvas.getContext('2d'); const tileSize = canvas.width / 3; // 每个瓦片的尺寸,刚好填满3x3区域 const tileMap = [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ]; // 玩家的瓦片坐标(初始在地图第二行第二列的空地) let playerTileX = 1; let playerTileY = 1; // 地图绘制偏移量,用来控制滚动 let offsetX = (canvas.width/2) - (playerTileX * tileSize); let offsetY = (canvas.height/2) - (playerTileY * tileSize); // 2. 绘制地图的函数 function drawMap() { // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 只绘制玩家周围3x3的瓦片:从playerTileX-1到playerTileX+1,Y同理 for (let y = playerTileY - 1; y <= playerTileY + 1; y++) { for (let x = playerTileX - 1; x <= playerTileX + 1; x++) { // 检查瓦片是否在地图范围内 if (y >= 0 && y < tileMap.length && x >=0 && x < tileMap[y].length) { const tileType = tileMap[y][x]; // 设置瓦片颜色:0=灰色障碍物,1=白色空地 ctx.fillStyle = tileType === 0 ? '#666' : '#fff'; // 计算瓦片在Canvas上的实际绘制位置:瓦片坐标*尺寸 + 偏移量 const drawX = x * tileSize + offsetX; const drawY = y * tileSize + offsetY; ctx.fillRect(drawX, drawY, tileSize, tileSize); // 可选:绘制瓦片边框,方便观察 ctx.strokeStyle = '#333'; ctx.strokeRect(drawX, drawY, tileSize, tileSize); } } } // 绘制玩家(固定在Canvas中心) ctx.fillStyle = '#ff0000'; ctx.beginPath(); ctx.arc(canvas.width/2, canvas.height/2, tileSize/4, 0, Math.PI*2); ctx.fill(); } // 3. 处理玩家移动的函数 function movePlayer(dx, dy) { // 计算新的玩家瓦片坐标 const newTileX = playerTileX + dx; const newTileY = playerTileY + dy; // 检查新位置是否是空地(1),且在地图范围内 if ( newTileY >= 0 && newTileY < tileMap.length && newTileX >=0 && newTileX < tileMap[newTileY].length && tileMap[newTileY][newTileX] === 1 ) { // 更新玩家的瓦片坐标 playerTileX = newTileX; playerTileY = newTileY; // 重新计算地图偏移量:让玩家所在瓦片回到中心 offsetX = (canvas.width/2) - (playerTileX * tileSize); offsetY = (canvas.height/2) - (playerTileY * tileSize); // 重绘地图 drawMap(); } } // 4. 绑定键盘事件,监听方向键 document.addEventListener('keydown', (e) => { switch(e.key) { case 'ArrowLeft': movePlayer(-1, 0); break; case 'ArrowRight': movePlayer(1, 0); break; case 'ArrowUp': movePlayer(0, -1); break; case 'ArrowDown': movePlayer(0, 1); break; } }); // 初始绘制地图 drawMap(); </script>
关键逻辑解释
- 偏移量计算:
offsetX = (canvas.width/2) - (playerTileX * tileSize)这个公式的作用是,让玩家所在的瓦片的中心点,刚好和Canvas的中心点重合。当玩家的瓦片坐标变化时,偏移量也跟着变化,地图就会向相反方向滚动。 - 3x3瓦片绘制:我们只遍历玩家周围的3个瓦片范围,避免了绘制整个17x3的大地图,性能更优。
- 移动判断:每次移动前先检查目标位置是否是空地(
tileMap[newY][newX] === 1),同时确保不超出地图边界,避免错误。
你可以直接运行这段代码,按方向键就能看到效果:红色的玩家始终在画布中心,地图随着按键左右滚动,始终只显示玩家周围的3x3瓦片区域,完全符合你的需求。
内容的提问来源于stack exchange,提问作者mnjq2006




