0

I'm trying to add sprites to my game engine and I've tried a whole bunch of things. The problem is that the game can run but my image never shows. EDIT: I have found by putting the image and src in the coin class constructor makes it render.

I've tried window.onLoad, img.onLoad, putting the vars in the constructor, splitting it into 2 functions (load and draw).

class gameObject {
    constructor(x,y,id){
        this.x = x;
        this.y = y;
        this.id = id;
        var velX, velY, width, height;
    }
    drawRect(){
        c.fillRect(this.x, this.y, this.width, this.height);
    }
    drawSprite(url){

            this.img = new Image();
            this.img.src = url;
            this.img.onload = function(){
                function draw(){
                    c.drawImage(this.img, this.x, this.y, this.width, this.height)
                }
                draw();
            }
    }
    move(){
        this.x += this.velX;
        this.y += this.velY;
    }
}
class Coin extends gameObject{
        constructor(x,y,id,img){
            super(x,y,id);
            this.velX = 0;
            this.velY = 0;
            this.width = 32;
            this.height = 32;
        }
        tick(){
            this.move();
        }
        render(){
            this.drawSprite("coin.png");
        }
    }

I need the image to show but it doesn't show and the game still runs.

GAMEDATA 1010
  • 31
  • 1
  • 3
  • 1
    Trying setting the onload before setting the src. This may be relevant: https://stackoverflow.com/questions/14648598/is-it-necessary-to-set-onload-function-before-setting-src-for-an-image-object – AaronHolland Aug 07 '19 at 02:27
  • change `this.img.onload = function(){` to `this.img.onload = () => {` or bind the correct `this` to it - you need to know how `this` works especially in asynchronous callbacks – Jaromanda X Aug 07 '19 at 02:48
  • also, why are you doing `function draw(){ c.drawImage(this.img, this.x, this.y, this.width, this.height) } draw();` ... seems unnecessary – Jaromanda X Aug 07 '19 at 02:53

2 Answers2

1

As per MDN, the value of this is undefined in function draw because it's a nested function inside a class declaration - and class declarations are parsed in strict mode.

One solution is to

  • use an arrow function for draw so it captures the lexical this value when it is assigned to a variable,
  • place the arrow function expression where the this value refers to the class instance instead of the image element, and
  • assign image onload handlers before setting their src attribute:
drawSprite(url){
    let draw = ()=>c.drawImage(this.img, this.x, this.y, this.width, this.height);
    this.img = new Image();
    this.img.onload = draw;
    this.img.src = url;
}

Further testing showed that CanvasRenderingContext2D method drawImage can not handle undefined values for x and y, and will draw nothing if they are.

class gameObject {
    constructor(x,y,id){
        this.x = x || 0; // default x and y to zero
        this.y = y || 0;
        this.id = id;
        var velX, velY, width, height;
    }

Defaulting undefined values to zero should help gettting further along with development.

traktor
  • 17,588
  • 4
  • 32
  • 53
0

Ok so the only solution I found was to move this.img & this.img.src to the class as shown here

class Coin extends gameObject{
    constructor(x,y,id){
        super(x,y,id);
        this.velX = 0;
        this.velY = 0;
        this.width = 32;
        this.height = 32;
        this.img = new Image();
        this.img.src = "coin.png";
    }
    tick(){
        this.move();
    }
    render(){
        this.drawSprite()
    }
}

and also apparently when waiting for the img to load also causes it to not show up so i just did this.

drawSprite(){
    c.drawImage(this.img, this.x, this.y, this.width, this.height);
}

I am also keeping it as the draw sprite function because I am going to make it also read from sprite sheets

GAMEDATA 1010
  • 31
  • 1
  • 3