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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:44:46