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

JavaScript游戏中更新Canvas图片源时如何消除闪烁?

解决Canvas图片切换时的闪烁问题

问题根源

你现在的代码存在两个核心问题导致闪烁:

  1. 每次gameLoop都会重复设置img.src,哪怕玩家生命值状态没变化,这会反复触发图片重新加载
  2. 图片加载是异步操作,还没加载完成就调用drawImage,会出现空白/旧图交替的闪烁现象;而且你没有预加载图片,切换时才开始加载,延迟更明显

解决办法

1. 预加载所有图片

提前把需要用到的两张图片加载完成,避免切换时临时加载导致的延迟

2. 仅在状态变化时切换图片

只有当生命值的状态(高于/低于50)发生改变时,才切换要显示的图片,避免重复设置src

3. 确保图片加载完成后再绘制

修改后的代码

HTML(无需改动)

<canvas id="canvas" width="200px" height="200px"></canvas>

JavaScript

let canvas;
let ctx;

let player;
// 存储预加载好的两张图片
const images = {
  healthy: new Image(),
  hurt: new Image()
};
// 记录当前显示的图片状态,避免重复切换
let currentImageState = 'healthy';

window.onload = function () {
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");

  player = {
    x: 0,
    y: 0,
    width: 20,
    height: 20,
    color: "#000000",
    health: 100
  }

  // 预加载图片,所有图片加载完成后再启动游戏循环
  let loadedCount = 0;
  const totalImages = Object.keys(images).length;
  
  // 图片加载完成的回调
  function onImageLoad() {
    loadedCount++;
    if (loadedCount === totalImages) {
      // 所有图片加载完成后启动游戏
      requestAnimationFrame(gameLoop);
    }
  }

  images.healthy.src = "img2";
  images.healthy.onload = onImageLoad;
  
  images.hurt.src = "img1";
  images.hurt.onload = onImageLoad;

  function draw() {
    // 每次绘制前先清空画布(避免残留旧内容)
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    ctx.fillStyle = player.color;
    ctx.fillRect(player.x, player.y, player.width, player.height);

    // 根据当前状态绘制对应的已加载图片
    const currentImg = currentImageState === 'healthy' ? images.healthy : images.hurt;
    ctx.drawImage(currentImg, 0, 0);
  }

  function gameLoop() {
    // 判断当前应该显示的图片状态
    const targetState = player.health < 50 ? 'hurt' : 'healthy';
    
    // 只有状态变化时才切换,避免重复操作
    if (targetState !== currentImageState) {
      currentImageState = targetState;
    }
    
    draw();
    requestAnimationFrame(gameLoop);
  }
}

关键改动说明

  • 新增images对象存储两张预加载的图片,确保绘制时用的是已经加载完成的资源
  • 用currentImageState记录当前显示状态,只有当生命值状态真的改变时才更新,避免每次循环重复触发图片加载
  • 绘制前调用clearRect清空画布,避免旧画面残留
  • 所有图片加载完成后才启动游戏循环,确保第一次绘制就有可用的图片

内容的提问来源于stack exchange,提问作者Charles Masgalas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:02:28