Interactivity, mouseDragged(), two discs

Again, i‘ll just answer :sweat_smile:
Q1:

You generally want to add final if you make a constant. For example :

final float SPEEDOFLIGHT = 3000000; // you‘ll never want to change that, cause the speedOfLight is a constant

//while 

float velocity = 5; // you might want to change the velocity later on, so you don‘t declare it as final. 

Final just means that the variable can’t be changed, which is exactly what you‘d want from a Constant. And generally constants are written all capitalized, just for convention…

As for what exactly that constant UNKNOWN stands for, it denotes what value your Flag should have, when you don‘t have anything flagged… Another example :

myFlag = -1;

if (myFlag != -1) { //so we have a flag value
// we can do something since we got a valid flag
}

// but using a constant is much smoother, since you never 
// know if you have to change that -1 to something different...

final int UNKNOWN = -1;
int myFlag = UNKNOWN; //since we don‘t have a flag right at the start

If (myFlag != UNKNOWN) { //in this case, we can change what UNKNOWN means 
// by changing the final int at the top, without having to look through all our code...

// do stuff
}

And we use -1, since your flag value can only be from 0 to 4 (5 discs in the array).
We could use any other value that those 5 numbers (0-4), but that‘s inconvinient if we want to suddenly have 100 discs and we used 44 as the UNKNOWN value… would be wierd, right?

Now we could use any negative value, but -1 is just the most obvious one… and you can just go to -2 if you need a second constant like NOTSURE, if you are not certain that discs overlap (doesn‘t make much sense in your case, but in other Codes that would be how it‘s used more or less).

As for Q2:
Relative Order always matters! But General Order not!
Now, relative Order would be this :

void draw() {
//this works
int a = 1;
int b = a+1;
int c = a+b;
//this doesn‘t work! 
int d = e; //we still don’t have a variable e, even if we declare it later...
int e = 5; //we only declared it after d, so d couldn‘t have known about it before. 
}

General Order :

float a = 1;
float e = 5;
float b = 19;
float z = 3;
//none are relative to each other, so the Order can be completely arbitrarily. 
// As Long as you don‘t use them before you declare them like 

float j = i+k;
float i = 9;
float k = 4;
//this won’t work!!!

That‘s pretty much all i‘d say…

I just noticed that Q2 isn‘t really answered all that well… so, no, as long as you don‘t use a variable that‘s not been declared before, you can Order the variables any way you want, doesn‘t matter where (Class, Global, Method).

4 Likes

When used to declare fields, variables & parameters, it permanently binds the value assigned to them.

Java convention dictates that final fields holding immutable values should have their names fully capitalized.

I’d also add the keyword static for such cases: static final int UNKNOWN = -1;

Just an arbitrary value outside valid range meaning that something is invalid or unknown.

It can matter when we are declaring its fields if some field happens to depend on the value of another.

After a class declaring block is finished we can access those fields in any order.

A constructor is just a special function which initializes a class instance state.

A function’s parameters are already initialized by passed arguments every time it’s invoked.

5 Likes

Thank you! On the order of elements, in an earlier version of this sketch (below), I provided values for dragX in

void setup() {
  size(400, 400);
  myDisc1 = new Disc(150); 
  myDisc2 = new Disc(250);
}

This was fine because all the other values were given in the Constructor. But, if I wanted to set values for two (more than one) variables in setup() would I follow the order of the Class or the Constructor?

int myFlag = 0;


Disc myDisc1;
Disc myDisc2;


void setup() {
  size(400, 400);
  myDisc1 = new Disc(150); 
  myDisc2 = new Disc(250);
}

void draw() {
  background(255);
  myDisc1.display();
  myDisc2.display();
  println(myDisc1.over()+" "+myDisc2.over()); // just for testing
}

void mouseDragged() {
  if (myFlag == 1) {
    myDisc1.move();
  } else if (myFlag == 2) {
    myDisc2.move();
  }
}

void mousePressed() {
  if (myDisc1.over()) {
    myFlag = 1;
  } else if (myDisc2.over()) {
    myFlag = 2;
  } else {
    myFlag = 0;
  }
}

class Disc { 
  int dragX;
  int dragY;
  int diam;


  // The Constructor
  Disc(int tempDragX) {
    dragX = tempDragX;
    dragY = 200;
    diam = 32;
  }

  void display() {
    stroke(0);
    noFill();
    ellipse(dragX, dragY, diam, diam);
  }

  boolean over() {
    if (dist(mouseX, mouseY, dragX, dragY) <= diam/2) {
      return true;
    }
    return false;
  }

  void move() {
    dragX = mouseX;
    dragY = mouseY;
  }
}
1 Like

there is a
https://processing.org/reference/class.html
for this but also not that clear,

a class has variables,
you can write in any order,
also in shortened form

int x,y,d;

the constructor contains the list of given parameter,
and expect to get them in that order when called from main

class Ball {
  color f = color(200, 200, 0); //_____ variable list any order
  int d;
  int x, y;
  Ball( int _x, int _y ) { //__________ parameter in this order
    y=_y; //___________________________ map to variable any order
    x=_x;
    d=33;
  }
  void draw() {
    fill(f);
    circle(x, y, d);
  }
}

//____________ main
Ball b;

void setup() {
  b = new Ball(20, 30); // canvas pos x,y in pix
}
void draw() {
  background(0,0,80);
  b.draw();
}

hope that is what your question was about.

2 Likes

Thank you @kll that is
exactly what my question was about (although I didn’t know
it). It’s the list of parameters in the Constructor!

Paul

The order in the constructor must be the same order like when you call the constructor in setup ()

This order is not important. It’s nice to set x before y.

I set diam first because I had to use its value to define x and y.

(It’s always better to use a variable than a number like you did with random(16,384)…)

1 Like

Yes, the Order of the parameters in the constructor and the order in which you declare the class using said constructor matters a lot, just like how it matters in any method with parameters.

void myMethod(String firstParam, int secondParam, Object andSoOn) {

}

myMethod(String firstParam, int secondParam, Object andSoOn); //this works

myMethod(int secondParam, String firstParam, Object andSoOn); //this won‘t work!!! 
2 Likes

somehow it is understandable,

when you give a parameter list v = new V(2,55,-3);
you must know what you are doing, like look at the place where the list is defined in the
constructor class V{ V(float x, float y , float z ) {} }

these structure is too simple, like as a CSV file ( must look header line what means what )
now a JSON is more as twice as long, but very clear defined
always give variable name and value…

JAVA not allow this (?this version?),
but very early in programming
i know from SQL this problem was understood and it is possible
to give
(2,55,-3)
so it will be understood as (float x, float y , float z ) from the definition,
OR
you can also write
(z=-3,y=55,x=2)

so, some code language allow this.


1 Like

How i wish there was a way to do (z = 10, x = 6, y = 2) !!! That‘s just so awesome and practical… why couldn‘t they integrate this… ugh… well, i know it‘s cause Java classes are compiled, but still :disappointed_relieved:

Although you could use HashMaps as an alternative, it‘s annoying to create a HashMap before a function and to have a reader within-.-

1 Like

float x=66;
float y=876;
float z=44;

v = new V(x,y,z);

Another example where the order of parameters matters is random() by the way.

random (100,-100) won’t work!

That information about the parameters in the constructor leads to my next question.

We now have excellent code for a Class that gives us draggable discs (thank you all!). I plan to use these discs in a GUI for selecting two of the three dimensions of a colour (Hue and Luminosity). dragX corresponds to Hue and dragY corresponds to Luminosity.

Now, the third dimension of the colour (Chroma) will be selected by a draggable disc that only moves in the x axis. A kind of slider.

I could change the Class to provide for discs that move in one or two dimension, I could have two methods, one for discs that move only in the x-axis and one for discs that move in 2D. I could adapt the Constructor so all the discs move the same way, but the value of the movement for the slider is constant. And so on…

So my question. When writing and using Classes, if one wants a new object that shares some but not all its functionality with objects from the existing Class at what level do you make the changes, element, molecular, atomic, subatomic?

2 Likes

I can‘t speak for the Computer version, but surprisingly random(100, -100); works perfectly on the IOS version.

I assume it sorts the values to min and max within the function.

1 Like

On the computer version,

println(random(100, -100)); -- gives 100 every time
println(random(-100, 100)); -- gives what you would expect

both give the same on the iOS version: – from -100 to 100.

I tested with random(0, -100)); – this gives 0 on computer, and results from -100 to zero on iOS so iOS is ignoring the order.

1 Like

Yes, for example Python (and processing Python mode) supports named parameters, with defaults. This tends to lead to one signature rather than multiple signatures as in Java. On the other hand, Java uses the types of arguments in order to match which of multiple identically names methods / constructor is being invoked by a given call – Python (mode) does not do this; it is duck-typed, and if the number of arguments can somehow match, they will be passed regardless of type.

UNIX / Linux shell scripts (eg bash) also use two overlapping systems of ordered parameters and/or named parameters.

3 Likes

There is no one correct approach – it depends on your problem, and sometimes is a question of style. However, if there has been a trend in general over time, it has been away from strict inheritence (extends) and towards using interfaces (implements) and/or encapsulation. I personally like interfaces for this kind of design – e.g. make an interface Draggable, make as many classes as you like (inherited, encapsulated, or not) that have implements Draggable, and then iterate through a list of draggables to pick one(s) that the mouse should be dragging and call the drag() method.

Aha. So, would I have a class called Slider that moves with only dragX

and then a subclass Disc that extends Slider where I inherit all of Slider and add the dragY

OR

would I have a superclass called Widget that has no movement

and a subclass called Slider that has the dragY

and then another subclass Disc that extends with dragX and dragY

I went with the second approach (extends) but I have a couple of questions. Please tell me what is wrong below and if I want a difference in display() (say red stroke for the sliders and black stroke for the discs) how would I do that?

@jeremydouglass

/*

*/

static final int UNKNOWN = -1; 
int myFlag = UNKNOWN;

static final int UNTOLD = -1; 
int myPennant = UNTOLD;

int numDiscs = 5; // moved from setup so available for mouseDragged()
int numSliders = 2;

Disc[] myDiscs; // Declare   PLURAL 
Slider[] mySliders; // Declare   PLURAL

// --------------------------------------------------
// Core functions 

void setup() {
  size(400, 400);


  myDiscs = new Disc[numDiscs]; // Create the array
  for (int i = 0; i < myDiscs.length; i++) {
    myDiscs[i] = new Disc(); // Create each object
  }



  mySliders = new Slider[numSliders]; // Create the array
  for (int j = 0; j < mySliders.length; j++) {
    mySliders[j] = new Slider(); // Create each object
  }
}





void draw() {
  background(255);

  for (Disc currentDisc : myDiscs) {
    currentDisc.display(); // Display each object
  }

  for (Slider currentSlider : mySliders) {
    currentSlider.display(); // Display each object
  }
}

// --------------------------------------------------
// Other functions 

void mouseDragged() {

  if ((myFlag >= 0) && (myFlag <= numDiscs)) {
    myDiscs[myFlag].move();
  } else if ((myPennant >= 0) && (myPennant < numSliders)) {
    mySliders[myPennant].move();
  } else {
    return;
  }
}



void mousePressed() {
  // reset 
  myFlag = UNKNOWN;
  myPennant = UNTOLD;

  //search


  for (int j=0; j < mySliders.length; j++) {
    if (mySliders[j].over()) {
      myPennant = j;
      return; // leave
    }
  }

  //


  for (int i=0; i < myDiscs.length; i++) {
    if (myDiscs[i].over()) {
      myFlag = i;
      return; // leave
    }
  }
}



// ==============================================

class Widget { 
  int dragX;
  int dragY;
  int diam;


  // The Constructor
  Widget() {
    diam = 32;
    dragX = int(random(diam/2, width-diam/2));
    dragY = int(random(diam/2, width-diam/2));
  }

  void display() {
    stroke(0);
    noFill();
    ellipse(dragX, dragY, 
      diam, diam);
  }

  boolean over() {
    if (dist(mouseX, mouseY, dragX, dragY) <= diam/2) {
      return true;
    }
    return false;
  }

  //
}//superclass
//

// ==============================================

class Disc extends Widget { 
  


  void move() {
    dragX = mouseX;
    dragY = mouseY;
  }
  //
}//subclass
//

// ==============================================

class Slider extends Widget { 
  


  void move() {
    dragX = mouseX;
    //dragY = mouseY; //if I want a vertical slider
  }
  //
}//subclass
//

As for how to change the fill in an ugly way, remove the noFill()/stroke(0); from the display() function and set the fill()/stroke() before calling the .display() for each Element (in draw).

Now to the elegant way :
•replace the display()'s fill(0); with fill(getFill());
•add a getFill color method (color getFill() {})
• Choose a way :

  1. override the getFill() method in the extended classes to return a specific color (return color(255,200,100):wink:
  2. •add a color field to the Widget class and return that in the getFill() method. (return myFill;)
    •you‘ll have to set the fill manually with the second way (either in constructor or for each instance).

Advantage of way 1 is that it‘s easy and fast.
Way 2 adds an extra field, but allows more modularity (you could change the color at will during Runtime).