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

Canvas精灵图首次加载失败仅刷新后显示问题求助

问题分析与修复方案

你的代码核心问题出在图片加载的回调绑定时机和图片尺寸获取的时机上,导致首次加载时图片还没加载完成就执行了绘制逻辑,只有缓存时才能正常显示。

具体问题点

  1. 构造函数中错误绑定onload回调
    你在构造函数里写了this.spritesheet.onload = loadImages(this);,这会立即执行loadImages函数,而不是把它作为回调函数赋值给onload。这导致图片还没设置src就调用了load()方法,而且onload最终被赋值成loadImages的返回值(undefined),图片真正加载完成时不会触发任何回调。

  2. 图片尺寸获取时机过早
    在load()方法里,设置src后马上获取this.spritesheet.width和height,这时候图片还没加载完成,这两个值都是0,只有当图片在缓存中时(刷新页面),才能立即拿到正确尺寸。

修复后的代码

修正Spritesheet类

class Spritesheet
{
    constructor(filename, rows, cols, x, y)
    {
        this.filename  = `./game/static/img/${filename}`;

        this.rows = rows;
        this.cols = cols;
    
        this.x = x;
        this.y = y;
    
        this.spritesheet = new Image();
        // 绑定回调函数而非立即执行,箭头函数保留当前实例的this上下文
        this.spritesheet.onload = () => this.onLoad();
    }

    // 启动图片加载:设置src
    load()
    {
        this.spritesheet.src = this.filename;
    }

    // 图片加载完成后的处理逻辑
    onLoad()
    {
        // 图片加载完成后再计算尺寸
        this.width = this.spritesheet.width / this.rows;
        this.height = this.spritesheet.height / this.cols;
        // 通知全局加载计数更新
        loadImages(this);
    }
}

修正loadImages函数

function loadImages(spritesheet)
{
    // 仅在图片真正加载完成后才递减计数
    if (--numOfImages <= 0) loadGame();
}

保持preloadStatic函数不变

function preloadStatic()
{
    var wallSpritesCount = 4;
    var floorSpritesCount = 10;

    numOfImages = wallSpritesCount + floorSpritesCount;
    
    for (let i = 0; i < wallSpritesCount; i++) {
        let filename = `wall/brick_gray_${i}.png`;
        let spritesheet = new Spritesheet(filename, 1, 1, 0, 0);
        wallSprites.push(spritesheet);
        // 创建实例后手动启动加载
        spritesheet.load();
    }

    for (let i = 0; i < floorSpritesCount; i++) {
        let filename = `floor/white_marble_${i}.png`;
        let spritesheet = new Spritesheet(filename, 1, 1, 0, 0);
        floorSprites.push(spritesheet);
        spritesheet.load();
    }
}

修复逻辑说明

  1. 构造函数中,将onload回调改为箭头函数,确保回调执行时this指向当前Spritesheet实例,且不会立即执行。
  2. 把图片尺寸计算移到onLoad方法中,确保只有图片加载完成后才获取有效尺寸。
  3. 创建Spritesheet实例后,手动调用load()方法设置图片src,正式启动加载流程。
  4. loadImages仅负责递减加载计数,当所有图片都加载完成后才调用loadGame(),保证游戏启动时所有资源已就绪。

这样修改后,首次加载时所有图片都会在加载完成后才触发计数递减,直到全部加载完毕才启动游戏,就不会出现首次加载不显示的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:13:12