issues passing an instance of one class into another class in P5.js

I am trying to convert some code and am nearly there but realize I do not understand how javascript and P5.js handles passing in an instance of one class to a method of another class. In this case, I am passing an instance of a paddle into the puck for a pong style game.

   ` //in the main program we initialize
    var puck = new Puck(); 
    var left = new Paddle(true);
    var right = new Paddle(false);
    //and then call the method like this
    puck.checkPaddleLeft(left);
    puck.checkPaddleRight(right);
...`


  `  //in the puck class we have this
    function Puck(){
     this.x = 600/2; // Place the puck in the middle of the x axis.
     this.y = 400/2; // Place the puck in the middle of the y axis.
     this.xspeed = 0; // Sets the initial puck speed along the x axis.
     this.yspeed = 0; // Sets the initial puck speed along the y axis.
     this.r = 12; // Establishes the radius of the puck at 12 pixels.
     //reset();

    Puck.protoype.checkPaddleLeft = function(p) { // Function to determine collision between the puck and the left paddle.
      if (y < p.y + p.h/2 && y > p.y - p.h/2 && this.x - this.r < p.x + p.w/2) {
        if (this.x > p.x) {
          var diff = y - (p.y - p.h/2);
          var rad = radians(45);
          var angle = map(diff, 0, p.h, -rad, rad);
          this.xspeed = 5 * cos(angle);
          this.yspeed = 5 * sin(angle);
          this.x = p.x + p.w/2 + this.r;
        }
      }
    }
...}`

When you try to run this, it returns "Cannot set property 'checkPaddleLeft' of undefined" Any assistance on how to structure such calls is appreciated.

Answers

  • edited November 12

    https://Forum.Processing.org/two/discussion/15473/readme-how-to-format-code-and-text

    http://JsBeautifier.org/

    1. http://Bl.ocks.org/GoSubRoutine/fa085945d45152786698f44a9523ccac
    2. http://p5js.SketchPad.cc/sp/pad/view/ro.CaQVvhrEKxAeXd/latest
    3. http://p5js.SketchPad.cc/sp/pad/view/ro.CwHWpJ$SP1EN8i/latest
  • edited November 13

    Oh man, this is so frustrating. I kept coming across this particular style for making P5.js classes, so I thought we had to! All the examples you linked to make classes the same way I do in Processing and even C++, so I guess I was just complicating things. Thanks for responding to my poorly formatted question ;)

    I will say that you did not answer my essential question, asking if there are issues or ways to pass in an object to a method in another class. I rebuilt my classes per your instructions/examples and the issue still remains - it says the property is undefined.

  • Answer ✓

    Oh man, this is so frustrating. I kept coming across this particular style for making P5.js classes, so I thought we had to!

    It's supposedly called progress :P

    Note that class is essentially synctatic-sugar to create an object with prototype-inherited 'methods' (my emphasis below):

    The class declaration creates a new class with a given name using prototype-based inheritance.

    The reason you'll find most documentation using the 'old' style is browser compatibility. ES6 is not yet fully supported...

    I'd also recommend reading You don't know JS - ES class (and the rest of the book) for a warning on the new 'class' keyword; especially if you're expecting JS 'classes' to work like those in other class-based languages.

    And if your sketch still returns errors we'll need to see the updated code to determine the problem ;)

  • edited November 13

    ES6 is not yet fully supported...

    According to this Browser compatibility table:
    https://Developer.Mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class#Browser_compatibility

    • Google's Chrome got class implementation available since version 42 (2015-Apr-14).
    • Apple's Safari: partially supported since version 9 (2015-Sep-30).
    • MS Edge: since version 13 (2015-Nov-11) w/o setting flags for it.
    • Mozilla's Firefox: since version 45 (2016-Mar-08).

    Thus since 2016-Mar-08, keyword class has become available for all of those 4 mainstream desktop browser families! :)>-

  • edited November 13

    For mobile, we've got these dates for the class ES6 feature: B-)

    • Mobile Chrome: since version 42 (2015-Apr-16).
    • iOS Safari: partially since version 9.3 (2016-Mar-20).
    • Mobile Firefox: since version 45 (2016-Mar-08).
  • I rebuilt my classes per your instructions/examples and the issue still remains...

    You should post your most recent runnable attempt here.
    Even better, post it online as well: https://OpenProcessing.org/sketch/create

    ... , asking if there are issues or ways to pass in an object to a method in another class.

    AFAIK, there are none! Just declare a parameter to hold the object argument, and access it within the method, just like you did at Puck::checkPaddleLeft(p). O:-)

  • edited November 13 Answer ✓

    In order to demonstrate better how to do it, I've converted this Processing Java Mode sketch:
    http://Studio.ProcessingTogether.com/sp/pad/export/ro.9qPrLGrYGkr2o

    To a p5.js sketch: http://Bl.ocks.org/GoSubRoutine/d0b7d3058d84970e83cf8685f8e69777

    At method Ball::colliding(c), its parameter c holds a passed Chamber object argument:

    colliding(c) {
      const { RAD } = c.constructor;
      return sq(c.x + RAD - this.x) + sq(c.y + RAD - this.y) < sq(RAD + Ball.RAD);
    }
    

    c.x, c.y are Chamber properties. While RAD is a Chamber static constant.

    Pretty much works very similarly to its original Java/JS Cross-Mode version: :>

    boolean colliding(Chamber c) {
      return sq(c.x + Chamber.RAD - x) + sq(c.y + Chamber.RAD - y) < sq(Chamber.RAD + RAD);
    }
    

    Below's its full code for you to check out here as well: :bz

    "index.html":

    <script async src=http://CDN.JSDelivr.net/npm/p5></script>
    <script defer src=sketch.js></script>
    

    "sketch.js":

    /**
     * Ball in the Chamber (v1.0.1)
     * GoToLoop (2017-Nov-13)
     *
     * Forum.Processing.org/two/discussion/24978/
     * issues-passing-an-instance-of-one-class-into-another-class-in-p5-js#Item_7
     *
     * Bl.ocks.org/GoSubRoutine/d0b7d3058d84970e83cf8685f8e69777
     *
     * Forum.Processing.org/two/discussion/10680/collision-colors#Item_14
     * Studio.ProcessingTogether.com/sp/pad/export/ro.9qPrLGrYGkr2o
     */
    
    "use strict";
    
    const BALLS = 4, balls = Array(BALLS),
          CHAMBERS = 8, chambers = Array(CHAMBERS),
          BG = 0o350;
    
    let bg;
    
    function setup() {
      createCanvas(640, 440);
    
      ellipseMode(CENTER).rectMode(CORNER).colorMode(RGB);
      strokeWeight(Ball.BOLD).stroke(Ball.STROKE);
    
      bg = color(BG);
    
      balls[0] = new Ball(50,  50,  4, 2);
      balls[1] = new Ball(50,  80,  3, 5);
      balls[2] = new Ball(100, 150, 4, 5);
      balls[3] = new Ball(300, 300, 6, 2);
    
      chambers[0] = new Chamber(1,   1,   'red');
      chambers[1] = new Chamber(599, 1,   'lightgreen');
      chambers[2] = new Chamber(1,   399, 'blue');
      chambers[3] = new Chamber(599, 399, 'pink');
      chambers[4] = new Chamber(300, 1,   'yellow');
      chambers[5] = new Chamber(300, 399, 'cyan');
      chambers[6] = new Chamber(1,   199, 'orange');
      chambers[7] = new Chamber(599, 199, 'magenta');
    }
    
    function draw() {
      background(bg);
    
      for (const b of balls) {
        for (const c of chambers)  if (b.colliding(c)) {
          b.c = c.c;
          break;
        }
    
        b.script();
      }
    
      for (const c of chambers)  c.display();
    }
    
    class Ball {
      static get DIM() {
        delete this.DIM;
        return this.DIM = 25;
      }
    
      static get RAD() {
        delete this.RAD;
        return this.RAD = this.DIM >> 1;
      }
    
      static get BOLD() {
        delete this.BOLD;
        return this.BOLD = 2;
      }
    
      static get STROKE() {
        delete this.STROKE;
        return this.STROKE = color(0);
      }
    
      static get INIT_FILL() {
        delete this.INIT_FILL;
        return this.INIT_FILL = color(0xff);
      }
    
      constructor(x, y, vx, vy) {
        this.x = x, this.y = y, this.vx = vx, this.vy = vy;
        this.c = Ball.INIT_FILL;
      }
    
      script() {
        return this.update().display();
      }
    
      update() {
        const { RAD } = Ball;
        if ((this.x += this.vx) > width  - RAD | this.x < RAD)  this.vx *= -1;
        if ((this.y += this.vy) > height - RAD | this.y < RAD)  this.vy *= -1;
        return this;
      }
    
      display() {
        fill(this.c).ellipse(this.x, this.y, Ball.DIM);
        return this;
      }
    
      colliding(c) {
        const { RAD } = c.constructor;
        return sq(c.x + RAD - this.x) + sq(c.y + RAD - this.y) < sq(RAD + Ball.RAD);
      }
    }
    
    class Chamber {
      static get DIM() {
        delete this.DIM;
        return this.DIM = 40;
      }
    
      static get RAD() {
        delete this.RAD;
        return this.RAD = this.DIM >> 1;
      }
    
      static get BOLD() {
        delete this.BOLD;
        return this.BOLD = 2;
      }
    
      static get STROKE() {
        delete this.STROKE;
        return this.STROKE = color(0);
      }
    
      constructor(x, y, c) {
        this.x = x, this.y = y, this.c = color(c);
      }
    
      display() {
        fill(this.c).rect(this.x, this.y, Chamber.DIM, Chamber.DIM);
        return this;
      }
    }
    
  • We (a student and I) are working this out on openProcessing already! http://www.openprocessing.org/sketch/473930 Please ignore the comments, they were added by the student as part of the process. Your example is massively helpful, tho I clearly need to read up on why you are using the const { RAD } = ... It looks to me like you are using it to make a new instance, not pass in a reference to an existing object? Thank you again for all of the thoughtful input!

  • edited November 14

    ... why you are using the const { RAD } = ...
    It looks to me like you are using it to make a new instance, ...

    That's called "object destructuring assignment": https://Developer.Mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring

    That doesn't instantiate anything. It's merely a shortcut to unbox properties outta objects into variables.

    For example, const { RAD } = Ball; is exactly equivalent to const RAD = Ball.RAD;
    And const { RAD } = c.constructor; is also the same as const RAD = c.constructor.RAD;

    BtW, c.constructor is the same as Chamber if a Chamber object argument is passed to method Ball::colliding(c).

    Therefore const { RAD } = c.constructor; is equal to const { RAD } = Chamber;
    And const { RAD } = Ball; can be written as const { RAD } = this.constructor;.

    All objects in JS have a property called constructor which points to their constructor function: https://Developer.Mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

Sign In or Register to comment.