Canvas中DrawImage在循环内无法绘制的问题求助
嘿,作为刚接触游戏编程和JavaScript的新手,遇到这种Canvas不渲染的问题太正常了,我帮你拆解下代码里的几个关键问题,改完应该就能正常显示了:
1. 图片加载的异步问题是核心
你的textures.onload回调写法不对,而且现在的代码是图片还没加载完成就调用了drawDungeon,这时候drawImage根本无法正常绘制图片。另外,onload的回调参数不是x,y,而是一个事件对象。
正确的做法是把所有依赖图片的绘制逻辑放到onload回调里,确保图片加载完成后再执行:
textures.onload = function() { createDungeon(6400, 4800); drawDungeon(Camera.posX, Camera.posY, canvas.width, canvas.height); } textures.src = "Images/textures.jpg";
2. 未声明的全局变量会破坏循环逻辑
你代码里的a、b、c都没有用let/var/const声明,会变成全局变量,导致嵌套循环的计数逻辑混乱——比如内层循环的a会覆盖外层的a,直接让循环跑错。
给所有循环变量加上let声明,示例:
for(let a=0; a<height; a+=32) { for(let b=0; b<width; b+=32) { // ... } }
3. drawImage的参数不完整
你现在调用ctx.drawImage(textures, b, a)只传了3个参数,这表示把整张图片从(b,a)的位置开始绘制,但你需要的是从tileset里裁剪出单个32x32的tile来画。假设你的tileset里第一个边框tile在左上角(0,0)位置,正确的drawImage写法应该是:
ctx.drawImage(textures, 0, 0, 32, 32, b, a, 32, 32);
参数依次是:源图片、源裁剪x坐标、源裁剪y坐标、源裁剪宽度、源裁剪高度、目标x坐标、目标y坐标、目标宽度、目标高度。
4. 优化drawDungeon的遍历逻辑(可选但重要)
你现在每次绘制一个tile都要遍历整个dungeon数组找匹配项,这对于6400x4800的大地图来说效率极低,完全没必要。其实可以通过坐标直接计算出对应的tile类型,不用存dungeon数组:
function drawDungeon(startX, startY, width, height) { for(let a=0; a<height; a+=32) { for(let b=0; b<width; b+=32) { // 计算当前tile的全局坐标 const globalX = b + startX; const globalY = a + startY; // 判断是不是地图边框 if(globalX === 0 || globalX === 6400 - 32 || globalY === 0 || globalY === 4800 - 32) { // 绘制边框tile ctx.drawImage(textures, 0, 0, 32, 32, b, a, 32, 32); } else { // 绘制白色地面 ctx.fillStyle = "#ffffff"; ctx.fillRect(b, a, 32, 32); } } } }
这样直接去掉dungeon数组,代码更简洁,运行效率也高很多。
修改后的完整代码
var canvas = document.getElementById("gameCanvas"); var ctx = canvas.getContext("2d"); canvas.width = 640; canvas.height = 480; var Camera = { posX: 0, posY: 0, } var textures = new Image(); textures.onload = function() { drawDungeon(Camera.posX, Camera.posY, canvas.width, canvas.height); } textures.src = "Images/textures.jpg"; // 直接通过坐标判断边框,无需dungeon数组 function drawDungeon(startX, startY, width, height) { for(let a=0; a<height; a+=32) { for(let b=0; b<width; b+=32) { const globalX = b + startX; const globalY = a + startY; // 判断是否为地图边框 if(globalX === 0 || globalX === 6400 - 32 || globalY === 0 || globalY === 4800 - 32) { ctx.drawImage(textures, 0, 0, 32, 32, b, a, 32, 32); } else { ctx.fillStyle = "#ffffff"; ctx.fillRect(b, a, 32, 32); } } } }
这样改完之后,Canvas应该就能正常显示带边框的地图了。如果还有问题,可以检查下textures.jpg的路径是否正确,确保图片能正常加载~
内容的提问来源于stack exchange,提问作者Ben Klayer

