Skip to content Skip to sidebar Skip to footer

HTML5 Canvas Images Are Not Loading Using DrawImage()

I'm following a tutorial on a flappy bird game by freeCodeCamp https://www.youtube.com/watch?v=pufKO5EG8nc But I'm doing it using a class to learn more about it. The problem is, th

Solution 1:

Your problem has to do with the scope - which refers to the accessibility of variables, objects and functions - and the meaning of the this keyword depending on the actual scope.

To get a better understanding let's have a look at the following example:

class Game {
  constructor() {
    console.log("Game constructor:", this);
    this.player = new Image();
    this.player.onload = this.draw;
    this.player.src = "https://picsum.photos/200/300";
  }

  draw() {
    console.log("draw:", this);
  }
}
let game = new Game();

If you click 'Run code snippet', you should see the following output in the console:


Game constructor: {}
draw: <img src="https://picsum.photos/200/300"></img>

As you can see a call to this inside draw() does not refer to the same thing anymore. In the first case it's an object instance of Game (hinted by the curly brackets) and in the second case it's an instance of a HTMLImageElement.

So your code simply fails because:

this.loadedSprites += 1;
if (this.loadedSprites >= this.sprites) {

don't reference the Game class's private variables loadedSprites and sprites - in fact it doesn't refer anything at all as it's simply undefined within the scope of the draw function thus loadedSprites doesn't ever get incremented.

One workaround is passing the context of the Game class to each Image instance using a new property e.g. .reference.

this.player = new Image();
this.player.reference = this;
this.player.onload = this.draw;

and use it inside draw() like:

draw() {
     this.reference.loadedSprites += 1;
}

Here's a complete example based on your code:

const canvas = document.querySelector("#canvas");
class Game {
  constructor(c) {
    this.c = c; //canvas
    this.ctx = c.getContext("2d"); // context
    this.sprites = 5;
    this.loadedSprites = 0;

    this.player = new Image(); // define images
    this.player.reference = this;
    this.bg = new Image();
    this.bg.reference = this;
    this.fg = new Image();
    this.fg.reference = this;
    this.north = new Image();
    this.north.reference = this;
    this.south = new Image();
    this.south.reference = this;

    this.pX = 10; // player starting location
    this.pY = 150;

    // set sprite locations and load.

    this.player.onload = this.draw;
    this.player.src = "https://picsum.photos/id/237/20/20";

    this.bg.onload = this.draw;
    this.bg.src = "https://picsum.photos/id/22/20/20";

    this.fg.onload = this.draw;
    this.fg.src = "https://picsum.photos/id/30/20/20";

    this.gap = 80;
    this.constant = this.north.height + this.gap;

    this.north.onload = this.draw;
    this.north.src = "https://picsum.photos/id/37/20/20";

    this.south.onload = this.draw;
    this.south.src = "https://picsum.photos/id/137/20/20";
  }

  //draw images
  draw() {
    let ref = this.reference;
    ref.loadedSprites += 1;
    if (ref.loadedSprites >= ref.sprites) {
      ref.ctx.drawImage(ref.bg, 0, 0);
      ref.ctx.drawImage(ref.north, 100, 0);
      ref.ctx.drawImage(ref.south, 0, 0 + ref.constant);
      ref.ctx.drawImage(ref.fg, 0, ref.c.height - ref.fg.height);
      ref.ctx.drawImage(ref.player, ref.pX, ref.pY);
    }
  }
}
let game = new Game(canvas);
<canvas id="canvas" width="512" height="512">
</canvas>

Post a Comment for "HTML5 Canvas Images Are Not Loading Using DrawImage()"