Wrapping preload(), setup() and draw() in an ES6 class

Class p5 is the original constructor already. :stuck_out_tongue:
It’s not been hacked like the reference stored in p5.prototype.Sprite. :space_invader:
Here’s a very simple “index.html” code proving so: :nerd_face:


index.html:

<script src=https://cdn.JsDelivr.net/npm/p5></script>
<script src=https://MolleIndustria.GitHub.io/p5.play/lib/p5.play.js></script>

<script>
  console.log('p5 constructor', p5 === p5.prototype.constructor);
  const Sprite = p5.prototype.Sprite;
  console.log('Sprite constructor', Sprite === Sprite.prototype.constructor);
</script>

Here’s my attempt on subclassing p5, based on my previous “Class p5 Extended” sketch: :sunglasses:


index.html:

<script defer src=https://cdn.JsDelivr.net/npm/p5></script>
<script defer src=sketch.js></script>

sketch.js:

/**
 * Class p5 Extended II (v1.1.1)
 * GoToLoop (2019-Jul-31)
 *
 * https://Discourse.Processing.org/t/
 * wrapping-preload-setup-and-draw-in-an-es6-class/13071/5
 *
 * https://Discourse.Processing.org/t/how-i-extends-class-in-p5-js/894/5
 *
 * https://CodePen.io/GoSubRoutine/pen/voJozR/left?editors=0011
 */

'use strict';

class Level extends p5 {
  static get FILENAME() {
    return 'https://upload.Wikimedia.org/wikipedia/commons/thumb/2/2e/' +
           'Processing_3_logo.png/480px-Processing_3_logo.png';
  }

  static redirectP5Callbacks(p) {
    p.preload = p.loadLevel.bind(p); // preload() callback has to be bind()
    p.setup = p.initLevel; // but callback setup() doesn't need bind()
    p.draw = p.runLevel.bind(p); // draw() has to be bind() like preload()
    p.mousePressed = p.mouseDragged = p.restartLevel; // optional for mouse
    p.touchStarted = p.touchMoved = p.restartLevel; // optional for touch
    p.keyPressed = p.keyReleased = p.restartLevel.bind(p); // required for key
  }

  constructor(levelNum) {
    super(Level.redirectP5Callbacks);
    this.levelNum = levelNum;
  }

  loadLevel() {
    this.img = this.loadImage(Level.FILENAME);
  }

  initLevel() {
    this.createCanvas(this.img.width, this.img.height);
    this.noLoop();

    this.rectMode(this.CORNER).ellipseMode(this.CENTER);
    this.colorMode(this.RGB).blendMode(this.BLEND);
    this.fill('yellow').stroke(0).strokeWeight(1.5).strokeCap(this.ROUND);
  }

  runLevel() {
    this.background('#' + this.hex(~~this.random(0x1000), 3));
    this.set(0, 0, this.img);
  }

  restartLevel() {
    this.redraw();
    return false;
  }

  // When bind() isn't needed, we can directly override the callback method:
  windowResized() {
    this.print('LevelNum: ' + this.levelNum);
    return false;
  }
}

// const levels = [ new Level(0), new Level(1) ];
const levels = Array.from({ length: 2 }, (v, i) => new Level(i));

BtW, I’ve hacked the callbacks w/ Function::bind(): :robot:

1 Like