从逻辑坐标到屏幕像素——棋盘绘制的数学基础设计截图坐标系统五子棋有两个坐标系统逻辑坐标board[row][col]row和col从0到14像素坐标Canvas上的x/y像素位置转换公式constcellSizesize/BOARD_SIZE;consthalfCellcellSize/2;// 逻辑坐标 → 像素坐标constpxhalfCellcol*cellSize;// xconstpyhalfCellrow*cellSize;// y// 像素坐标 → 逻辑坐标constcolMath.round((x-halfCell)/cellSize);constrowMath.round((y-halfCell)/cellSize);为什么需要halfCell偏移Canvas坐标系 (0,0)在左上角 ┌──────────────────────┐ │ · · · · ·│ ← 网格交点在halfCell, halfCellcellSize, ... │ │ │ · · · · ·│ │ │ │ · · · · ·│ └──────────────────────┘ 如果不偏移halfCell第一条线会在(0,0)处棋子会画在边缘上。 偏移halfCell后第一条线在中心棋子有边距。网格线绘制代码ctx.strokeStyleLINE_COLOR;ctx.lineWidth1;for(leti0;iBOARD_SIZE;i){constposhalfCelli*cellSize;// 水平线ctx.beginPath();ctx.moveTo(halfCell,pos);// 起点左边界ctx.lineTo(size-halfCell,pos);// 终点右边界ctx.stroke();// 垂直线ctx.beginPath();ctx.moveTo(pos,halfCell);// 起点上边界ctx.lineTo(pos,size-halfCell);// 终点下边界ctx.stroke();}关键细节水平线从halfCell到size - halfCell不画到Canvas边缘每条线用beginPath()开始stroke()结束lineWidth 1使用1像素细线星位绘制conststars:number[][][[3,3],[3,11],[7,7],[11,3],[11,11]];ctx.fillStyleSTAR_COLOR;for(conststarofstars){constsxhalfCellstar[1]*cellSize;constsyhalfCellstar[0]*cellSize;ctx.beginPath();ctx.arc(sx,sy,3,0,Math.PI*2);ctx.fill();}五个星位的位置0 1 2 3 ... 7 ... 11 ... 14 ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ 0 │ │ │ │ │ │ │ │ │ │ │ ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ 3 │ │ │ ★ │ │ │ │ ★ │ │ ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ 7 │ │ │ │ │ ★ │ │ │ │ │ ← 天元 ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ 11│ │ │ ★ │ │ │ │ ★ │ │ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘星位半径3像素用fill()填充实心圆。点击坐标转换privatehandleClick(event:ClickEvent):void{constcellSizethis.canvasSize/BOARD_SIZE;constxevent.x;constyevent.y;constcolMath.round((x-cellSize/2)/cellSize);constrowMath.round((y-cellSize/2)/cellSize);if(row0rowBOARD_SIZEcol0colBOARD_SIZE){this.onCellClick(row,col);}}逆向转换减去halfCell偏移除以cellSize得到浮点坐标Math.round四舍五入到最近的交点边界检查转换后验证row和col在合法范围内。坐标转换的精度Math.round确保用户点击交点附近时能正确识别如果cellSize 20px, halfCell 10px 点击 (15, 15) → col round((15-10)/20) round(0.25) 0 点击 (25, 25) → col round((25-10)/20) round(0.75) 1 点击 (20, 20) → col round((20-10)/20) round(0.5) 1 (向上取整)每个交点的点击区域是cellSize × cellSize的正方形以交点为中心。自适应尺寸// onAreaChange中获取实际尺寸.onAreaChange((_oldValue:Area,newValue:Area){constwnewValue.width;if(typeofwnumber){this.canvasSizew;if(this.isReady){this.drawBoard();}}})Canvas的宽度设为100%通过aspectRatio(1)保持正方形。实际像素尺寸由onAreaChange动态获取确保在不同屏幕上都能正确绘制。总结坐标转换是Canvas游戏开发的基础halfCell偏移确保棋子不画在边缘正向转换逻辑坐标 → 像素坐标绘制用逆向转换像素坐标 → 逻辑坐标点击用Math.round实现最近交点吸附onAreaChange自适应不同屏幕尺寸这些技巧适用于所有网格类游戏的Canvas绘制。