Search code examples
javascripthtmlhtml5-canvas

Canvas sprites images only loads after a page refresh


I have read the previous posts on this and I understand that the image isn't being loaded initially because I am drawing it before it's loaded, and that when I refresh it, because the browser caches the image it is drawn.

Firsly, I have a Spritesheet class:

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.spritesheet.onload = loadImages(this);
    }

    load()
    {
        this.spritesheet.src = this.filename;
        this.width = this.spritesheet.width / this.rows;
        this.height = this.spritesheet.height / this.cols;
    }

}

Then I have the loadImages function that call the method load(spritesheet):

function loadImages(spritesheet)
{
    spritesheet.load();
    if (--numOfImages <= 0) loadGame();
    
}

Inside my window.onload call I have a function called preloadStatic() that populates 2 arrays for certain Sprites that the game uses:

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);
    }

    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);
    }
}

But the sprites only load after a page refresh.

The logic that I am using it that, when the window loads, it preloads the static files and sets the variable numOfImages, when it loops through all the possible sprites I need to be loaded inside the Spritesheet constructor it sets a new Image() then call the onload method. Then inside the onload method it calls the Spritesheet.load() which set's the source of the image to the filename. Once then this has been called for every Spritesheet the variable numOfImages is decremented to 0 and the game then loads. But this only works when refreshing the page.

Sorry that I have asked a question that has previously been asked but I couldn't find a solution, I have tried using the onload method which has been described multiple time. Thank you for reading this.


Solution

    1. You run loadImage(this) immediately in the constructor
    2. Your image will start loading when you set src so you can't do that in the load function
    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();
            // added `() => `
            this.spritesheet.onload = () => loadImages(this);
            // added line below
            this.spritesheet.src = this.filename;
        }
    
        load()
        {
            // removed this.spritesheet.src = this.filename;
            this.width = this.spritesheet.width / this.rows;
            this.height = this.spritesheet.height / this.cols;
        }
    
    }