-1

requestAnimationFrame does not return a regular this when I use it in a class.

I've been looking all posts about the subject (tried to encapsulate the step() function as an anonymous function into animate...), but I still have the same issue.

class Sprite {

  constructor(canvas, imageSrc) {
    this.canvas = canvas;
    this.img = new Image();
    this.img.src = imageSrc;
    this.height = 18;
    this.width = 16;
    this.scale = 4;
    this.scaledWidth = this.scale * this.width;
    this.scaledHeight = this.scale * this.height;
    this.cycleLoop = [0];
    this.currentLoopIndex = 0;

    this.img.onload = () => {
      this.init();
    }
  }

  init() {
    this.ctx = this.canvas.getContext('2d');
    this.ctx.webkitImageSmoothingEnabled = false;
    this.ctx.mozImageSmoothingEnabled = false;
    this.ctx.imageSmoothingEnabled = false;
  }

  drawFrame(frameX, frameY, canvasX, canvasY) {
    this.ctx.drawImage(
      this.img,
      frameX * this.width,
      frameY * this.height,
      this.width,
      this.height,
      canvasX,
      canvasY,
      this.scaledWidth,
      this.scaledHeight
    );
  }

  animate() {
    requestAnimationFrame(this.step());
  }

  step() {
    console.log(this);
    console.log(this.ctx);
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

    this.drawFrame(this.cycleLoop[this.currentLoopIndex], 0, 0, 0);
    this.currentLoopIndex++;


    if (this.currentLoopIndex >= this.cycleLoop.length) {
      this.currentLoopIndex = 0;
    }
    requestAnimationFrame(this.step());
  }
}

In step(), the first console.log(this) shows a Character object with ctx attributes. The second console.log(this.ctx) is undefined for some reasons.

So I get a:

Uncaught TypeError: Cannot read property 'clearRect' of undefined
    at Character.step (sprite.js:49)
Cornelius
  • 378
  • 1
  • 2
  • 12
  • Duplicate of [Es6 class “this” in callback of requestAnimationFrame?](https://stackoverflow.com/questions/49197700/es6-class-this-in-callback-of-requestanimationframe) and also [Use requestAnimationFrame in a class](https://stackoverflow.com/questions/28908999/use-requestanimationframe-in-a-class) – Herohtar Jun 22 '19 at 09:28
  • Also, you should not include the parentheses when passing a function directly to `requestAnimationFrame`, as that will just call the function immediately instead of passing a reference to it. (`requestAnimationFrame(this.step)`) – Herohtar Jun 22 '19 at 09:31
  • Tried the "ES6 Class "this"" solution. Nothing gets executed it seems. Tried the `this.step` without parentheses too. – Cornelius Jun 22 '19 at 09:35
  • In the case of that solution you are *not* passing the function directly, but instead using an arrow function, so you do need the parentheses: `requestAnimationFrame(() => this.step())` – Herohtar Jun 22 '19 at 09:36
  • yep, both ain't working though :) – Cornelius Jun 22 '19 at 09:55
  • Are you calling `step()` before the `ctx` has been created? Meaning `step()` is called before the `onload` > `this.init()` > `this.ctx = this.canvas.getContext('2d')`? – Brett DeWoody Jun 22 '19 at 10:00

2 Answers2

2
this.canvas = canvas;

is defined inside the construtor of your Sprite class.

this.ctx = this.canvas.getContext('2d');

however is defined inside the callback function for the Image's onload event. So my best guess is the time you call the animate() method on a Sprite instance the onload event didn't fire yet thus the context isn't defined.

obscure
  • 11,916
  • 2
  • 17
  • 36
  • Thanx! So the idea is to create a Promise.all loading all images first, before I trigger anything else I guess. – Cornelius Jun 22 '19 at 11:14
  • 1
    No problem @Cornelius! In any case I'd move the initialization of this.ctx into the constructor. – obscure Jun 22 '19 at 11:38
1

It appears step() is being called before the ctx is defined. Most likely because step() is called before the img.onload() callback which creates the ctx.

Make sure to call step() after init().

Or setup the ctx in the constructor, with:

this.ctx = canvas.getContext('2d');
Brett DeWoody
  • 59,771
  • 29
  • 135
  • 184