Canvas中fillText不显示求助:角色按键移动时无法渲染文本
解决Canvas中fillText无法显示的问题
我看了你的代码,问题主要出在渲染时机和绘制顺序上,下面给你拆解原因和解决办法:
核心问题分析
你的render函数通过requestAnimationFrame持续重绘Canvas上的tileset和角色sprite,而你在move键盘事件里调用的fillText,刚绘制出来就会被下一次render的重绘操作覆盖掉——因为每次render都会重新绘制整个地图和角色,相当于把画布“刷新”了一遍,文本自然留不住。另外,你把文本画在(0,0)位置,如果view.x有偏移的话,这个位置可能已经超出了当前可见的视口范围,就算没被覆盖也看不到。
具体解决方案
1. 将文本渲染逻辑移到render函数中
把绘制文本的代码放到render里,这样每次画布重绘时都会同步绘制文本,不会被覆盖。同时可以加一个控制变量,用来决定什么时候显示文本。
2. 调整文本位置到可见区域
不要把文本画在(0,0),可以设置一个固定的屏幕位置(比如距离左上角20px的地方),确保文本在用户可见的视口范围内。另外别忘了设置font属性,默认的Canvas文本字体很小,可能即使显示了也看不清。
3. 优化文本显示的触发逻辑
可以在每次移动时标记需要显示文本,比如设置一个定时器让文本显示几秒后自动消失,或者根据moveCount变化来控制显示状态。
修改后的代码示例
先添加控制文本显示的变量:
// 新增变量:控制要显示的文本内容和显示时长 let showPromptText = ""; let textExpireTime = 0;
修改move函数,触发文本显示:
function move(e) { if (e.keyCode == 39) { boatPosX += 5; view.x -= 5; moveCount++; // 设置要显示的文本,以及显示时长(比如2000毫秒) showPromptText = theArray[0].question; textExpireTime = Date.now() + 2000; console.log(theArray[0].question); } // 其他方向的移动逻辑同理,可以按需添加文本触发 if (e.keyCode == 37) { boatPosX -= 5; view.x += 5; moveCount++; } if (e.keyCode == 38) { boatPosY -= 5; view.y += 5; // 注意你之前写的是view.Y,要改成小写y moveCount++; } if (e.keyCode == 40) { boatPosY += 5; view.y += 5; // 同样修正为小写y moveCount++; } }
最后修改render函数,在合适的位置绘制文本:
function render(viewport) { // 先清屏,避免画面残留(可选但建议添加) context.clearRect(0, 0, canvas.width, canvas.height); context.save(); context.translate(view.x, view.y); // 绘制tileset的代码保持不变 for (let i = 0; i < mapArray.length; i++) { for (let j = 0; j < mapArray[i].length; j++) { if (mapArray[i][j] == 0) { this.sprite.draw( background, 190, 230, 26, 26, i * this.sprite.width, j * this.sprite.height, this.sprite.width, this.sprite.height ); } if (mapArray[i][j] == 1) { this.sprite.draw( background, 30, 30, 26, 26, i * this.sprite.width, j * this.sprite.height, this.sprite.width, this.sprite.height ); } if (mapArray[i][j] == 2) { this.sprite.draw( background, 200, 20, 26, 26, i * this.sprite.width, j * this.sprite.height, this.sprite.width, this.sprite.height ); } } } this.ship.drawimage(boat, boatPosX, boatPosY, 50, 50); if(isPositionWall(boatPosX, boatPosY)) { boatPosX = oldPosX; // 你之前写的是oldPosY,这里应该是oldPosX才对 console.log("collision"); } context.restore(); // 绘制文本:在restore之后,用原始坐标系绘制固定位置的文本 if (showPromptText && Date.now() < textExpireTime) { context.fillStyle = "red"; context.font = "18px Arial"; // 设置清晰的字体大小和类型 context.fillText(showPromptText, 20, 30); // 距离左上角20,30的可见位置 } requestAnimationFrame(render); }
额外小修正
我还发现你代码里的小错误:
- 移动上下方向时,你写的是
view.Y,要改成小写的view.y,否则不会生效 - 碰撞检测里你把
boatPosX重置为oldPosY,应该是oldPosX才符合逻辑
内容的提问来源于stack exchange,提问作者Limpuls
相关产品推荐
相关产品推荐

