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

JavaScript状态引擎初次尝试失败,画布内容无法切换

解决Canvas状态切换时旧内容残留的问题

嘿,别担心,刚接触编程和Canvas遇到这种问题太正常啦!你的核心问题其实是Canvas的绘制是叠加式的——每次你调用drawBox画新盒子,之前画的内容不会自动消失,得手动清除画布才行。另外你的代码里还有个小bug,也得一起修正,不然帧率会有问题。

问题分析

  1. 未清除画布:每次切换状态后,新的盒子画在旧盒子上面,导致所有盒子都保留在画布上。
  2. setInterval参数错误:setInterval的第二个参数是毫秒数,你传入的FPS=60意味着每60毫秒执行一次,这会导致每秒仅执行16次左右,远低于你想要的60帧。正确的计算应该是1000/FPS,也就是每16.67毫秒执行一次。

解决方案步骤

1. 添加清屏函数

先写一个简单的函数,用来清除整个Canvas的内容:

function clearCanvas() {
  // 从(0,0)开始,清除整个画布的宽高范围
  ctx.clearRect(0, 0, c.width, c.height);
}

2. 修复帧率设置

把ticker函数里的setInterval参数改成1000/FPS:

function ticker(){
  setInterval(initGame, 1000/FPS);
}

3. 每次绘制前清屏

在initGame函数里,调用checkState之前先执行清屏,这样每次状态更新前都会把旧内容清除干净:

function initGame(){
  clearCanvas(); // 先清屏
  checkState();
  counter++;
}

修改后的完整代码

<!DOCTYPE html> 
<html> 
<body onload="init()"> 
  <canvas id="myCanvas" width="1024" height="1024" style="border:1px solid #d3d3d3;"></canvas> 
  <script> 
    var FPS = 60; 
    var counter = 0; 
    var currentState = 0; 
    var intervalTime = 300; 
    var c = document.getElementById("myCanvas"); 
    var ctx = c.getContext("2d"); 

    function init(){
      ticker(); 
    } 

    function ticker(){
      setInterval(initGame, 1000/FPS); 
    } 

    function initGame(){
      clearCanvas();
      checkState(); 
      counter++; 
    } 

    function drawBox(x,y){ 
      ctx.fillStyle="#FF0000"; 
      ctx.fillRect(x, y, 50, 50); 
    } 

    function clearCanvas() {
      ctx.clearRect(0, 0, c.width, c.height);
    }

    function checkState(){ 
      switch(currentState){ 
        case 0: 
          console.log("case 0"); 
          drawBox(0,0); 
          if (counter === intervalTime){ 
            counter = 0; 
            currentState = 1; 
          } 
          break; 
        case 1: 
          console.log("case 1"); 
          drawBox(50,0); 
          if (counter === intervalTime){ 
            counter = 0; 
            currentState = 2; 
          } 
          break; 
        case 2: 
          console.log("case 2"); 
          drawBox(100,0); 
          if (counter === intervalTime){ 
            counter = 0; 
            currentState = 0; 
          } 
          break; 
      } 
    } 
  </script> 
</body> 
</html>

额外小建议

  • 对于游戏状态管理,你可以把每个状态的逻辑封装成独立的函数(比如state0()、state1()),这样代码会更清晰,后期拓展关卡也更方便。
  • 记得Canvas的绘制上下文(ctx)会保留之前的设置(比如fillStyle),如果不同状态需要不同样式,最好每次绘制前明确设置,避免样式混乱。

内容的提问来源于stack exchange,提问作者Jack Smillie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:58:38