Interactivity, mouseDragged(), two discs

The disc (see below) moves when it is dragged. That is fine.

How do I have two discs and have them move independently? So if I drag disc1 it moves, and disc2 does not move and if I drag disc2 that moves and disc1 does not move.

I would also like to keep the two discs away from each other by distance r so they do not get to overlap or interfere with each other.

int dragX = 200;
int dragY = 200;

void setup() {
  size(400, 400);
  stroke(0);
  noFill();
  
}

void draw() {
  background(255);
  ellipse(dragX, dragY, 35, 35); // disc1
}

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

You need
dragX and dragY for each ellipse; so

  • drag1X and drag1Y and
  • drag2X and drag2Y

Upon mousePressed first find out which ellipse has been clicked (if dist(...)

Store the result in a variable c

In mouseDragged check c and only change the Position of one ellipse (if(c.....)

1 Like

Thanks @Chrisir

I tried (see below) but it didn’t work out. I made up much of the code based on Lingo. Bizarrely when I run it, the number 413 is printed into the console!!!

What have I done wrong or not done?

class Sprite {
  float x;
  float y;
}


int drag1X = 150;
int drag1Y = 200;
int drag2X = 250;
int drag2Y = 200;
Sprite discOne = new Sprite();
Sprite discTwo = new Sprite();


void setup() {
  size(400, 400);
  stroke(0);
  noFill();
}

void draw() {
  background(255);
  ellipse(drag1X, drag1Y, 32, 32); // disc1
  ellipse(drag2X, drag2Y, 32, 32); // disc2
}



void mouseDragged() {
  if (pointInCircle(mouseX, mouseY, discOne.x, discOne.y, 16)) {
  drag1X = mouseX;
  drag1Y = mouseY;
  }
  if (pointInDisc(mouseX, mouseY, discTwo.x, discTwo.y, 16)) {
  drag2X = mouseX;
  drag2Y = mouseY;
  }
}



boolean pointInDisc(float x, float y, float a, float b, float r) {
  if (dist(x, y, a, b) <= r) {
    return true;
  } else {
    return false;
  }
}

You missed to do your house cleaning:

  • At the moment in your code is a wild mix of usage of the class (with undefined x,y) and usage of dragX etc.

Read the tutorial about objects please and get a constructor

https://www.processing.org/tutorials/objects/

when both objects derived from the class work, get rid of all drag1X etc.

I went with your first suggestion @Chrisir and now it works. Is it also correct?
Thanks.

int myDisc = 0; //flag - should be Boolean?

int drag1X = 150;
int drag1Y = 200;
int drag2X = 250;
int drag2Y = 200;

int r = 16; //radius of disc

void setup() {
  size(400, 400);
  stroke(0);
  noFill();
}

void draw() {
  background(255);
  ellipse(drag1X, drag1Y, 2*r, 2*r); // disc1
  ellipse(drag2X, drag2Y, 2*r, 2*r); // disc2

  if (dist(mouseX, mouseY, drag1X, drag1Y) <= r) {
    myDisc = 1;
  } else if (dist(mouseX, mouseY, drag2X, drag2Y) <= r) {
    myDisc = 2;
  } else {
    myDisc = 0;
  }
  //println(myDisc);
}

void mouseDragged() {

  if (myDisc == 1) {
    drag1X = mouseX;
    drag1Y = mouseY;
  } else if (myDisc == 2) {
    drag2X = mouseX;
    drag2Y = mouseY;
  }
}
1 Like

it’s not bad.

But when you drag the right circle over the left circle, suddenly the left circle is the active one.

Look at this again:

Upon the function mousePressed first find out which ellipse has been clicked ( if dist(... )

Store the result in a variable c

Like this?

int myDisc = 0; //flag

int drag1X = 150;
int drag1Y = 200;
int drag2X = 250;
int drag2Y = 200;

int r = 16; //radius of disc

void setup() {
  size(400, 400);
  stroke(0);
  noFill();
}

void draw() {
  background(255);
  ellipse(drag1X, drag1Y, 2*r, 2*r); // disc1
  ellipse(drag2X, drag2Y, 2*r, 2*r); // disc2
  

  //println(myDisc);
}

void mouseDragged() {

  if (myDisc == 1) {
    drag1X = mouseX;
    drag1Y = mouseY;
  } else if (myDisc == 2) {
    drag2X = mouseX;
    drag2Y = mouseY;
  }
}



void mousePressed() {
    if (dist(mouseX, mouseY, drag1X, drag1Y) <= r) {
    myDisc = 1;
  } else if (dist(mouseX, mouseY, drag2X, drag2Y) <= r) {
    myDisc = 2;
  } else {
    myDisc = 0;
  }
}
1 Like

Nice.

There are probably many ways to do this

Now make it via the class and 2 objects :wink:

Like this (with Class and two objects)?

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();
}

void mouseDragged() {
  myDisc1.move();
  myDisc2.move();
}

void mousePressed() {
  if (dist(mouseX, mouseY, myDisc1.dragX, myDisc1.dragY) <= myDisc1.diam/2) {
    myFlag = 1;
  } else if (dist(mouseX, mouseY, myDisc2.dragX, myDisc2.dragY) <= myDisc2.diam/2) {
    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);
  }

  void move() {
    if (myFlag == 1) {
      myDisc1.dragX = mouseX;
      myDisc1.dragY = mouseY;
    } else if (myFlag == 2) {
      myDisc2.dragX = mouseX;
      myDisc2.dragY = mouseY;
    }
  }
}
1 Like

Almost.

BUT some remarks

in mousePressed() you have this:

if (dist(mouseX, mouseY, myDisc1.dragX, myDisc1.dragY) <= myDisc1.diam/2) {

That looks complicate: A lot of references to one object is an indicator that we want to have this in the class. Also, both lines almost are the same.

Eg. make a method over inside the class.

And then in mousePressed() :
if(myDisc1.over) myFlag = 1;

In the class you have this:

   if (myFlag == 1) {
      myDisc1.dragX = mouseX;
      myDisc1.dragY = mouseY;
    } else if (myFlag == 2) {
      myDisc2.dragX = mouseX;
      myDisc2.dragY = mouseY;
    }

This is obviously not in the spirit of OOP (object oriented programming) and won’t work when you have 100 circles in an array. You also use an object declared on Sketch level (before setup()) inside the class. Bad, because the purpose of the class is to be reusable in another sketch and there, the global vars (objects) could have different names or be in an array. Then your class won’t work anymore. Don’t use objects in a class (objects of the class itself), just use the variables inside the class.

Next exercise for you could be to use 5 circles in an array.

Chrisir

Sketch addresses issue 2:


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();
}

// -----------------------------------------------------------------------

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

void mousePressed() {
  if (dist(mouseX, mouseY, myDisc1.dragX, myDisc1.dragY) <= myDisc1.diam/2) {
    myFlag = 1;
  } else if (dist(mouseX, mouseY, myDisc2.dragX, myDisc2.dragY) <= myDisc2.diam/2) {
    myFlag = 2;
  } else {
    myFlag = 0;
  }
}

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

class Disc { 

  int dragX;
  int dragY=200;

  int diam = 32;

  color colDisc = color (random(100, 190));

  // The Constructor
  Disc(int tempDragX) { 
    dragX = tempDragX;
  }

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

  void move() {
    dragX = mouseX;
    dragY = mouseY;
  } // method 
  //
}//class
//
4 Likes

I have tried to address your remarks 1 and 2. Have I?

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;
  boolean over;


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

  void display() {
    stroke(0);
    noFill();
    ellipse(dragX, dragY, diam, diam);
    over = dist(mouseX, mouseY, dragX, dragY) <= diam/2;
  }


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

I‘m just gonna answer for the time being, since you‘re still missing the 3rd part anyway.

For the 1st part, you‘d want to make a method over(), not a boolean over. Although it might seem like it does the same, it does not.

Your code will use complex distance calculations every time it displays the disc (so 2 times per Frame). While a method would only perform that calculation on a mousePressed Event.

What you need is a method that returns a boolean as value. The „void“ you‘re probably used to is just a way to say that this method does not return a variable. So to return a variable, you have to use that Class name instead, and add a return value; at the end.

I‘ll make an example for Strings just to show the principle behind it.

String myString () {
String s = „Hello“;
return s;
}

println(myString()); // Prints „Hello“

Now you‘ll need to implement this as a boolean method. And it should return wether your “over“ calculation is true or false.

As for part 2, that issue was already addressed in Chrisir‘s last post‘s Code, so it‘s just copy paste in the end. Not much that could go wrong there, so all is good.

Now you just need to implement part 3 and you‘re good to go :sweat_smile:

Hint : An array would be very similar to your sketch, since you already use numbers in your variable names anyways :wink:

3 Likes

@Lexyth @Chrisir
I want to get this right before I tackle the array and five discs.
Thanks!

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;
  }
}

And perhaps with arrays and five rings…

int myFlag = 0;


Disc[] myDisc; // Declare

int numDiscs = 5;

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

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

void draw() {
  background(255);


  for (int i=0; i < myDisc.length; i++) {
    myDisc[i].display(); // Display each object
  }


  //  for (int i=0; i < numDiscs; i++) {
  //  myDisc[i].display(); // Display each object
  //}

}

void mouseDragged() {

  for (int i=0; i < myDisc.length; i++) {
    if (myFlag == i) {
      myDisc[i].move();
    }
  }
}

void mousePressed() {

  for (int i=0; i < myDisc.length; i++) {
  if (myDisc[i].over()) {
      myFlag = i;
    }
  }
}
class Disc { 
  int dragX;
  int dragY;
  int diam;


  // The Constructor
  Disc() {
    dragX = int(random(16,384));
    dragY = int(random(16,384));
    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;
  }
}

The entire for loop is unnecessary. Just use myFlag as index

Nicely done, and as you see, no changes in the class were necessary

Not needed (or move it inside setup)

Thanks for your guidance. Learned much. I don’t understand the comment about mouseDragged()

void mouseDragged() {

  for (int i=0; i < myDisc.length; i++) {
    if (myFlag == i) {
      myDisc[i].move();
    }
  }
}

myDisc[myFlag].move();

No for loop




final int UNKNOWN = -1; 
int myFlag = UNKNOWN;
Disc[] myDiscs; // Declare   PLURAL 

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

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

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

void draw() {
  background(255);

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

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

void mouseDragged() {
  if (myFlag == UNKNOWN)
    return;  // leave 

  myDiscs[myFlag].move();
}

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

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

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

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


  // The Constructor
  Disc() {
    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;
  }

  void move() {
    dragX = mouseX;
    dragY = mouseY;
  }
  //
}//class
//
2 Likes

Thank you @Chrisir
Just two questions for me, and so anyone who learns from this example will understand what you have done.

Q1
Please will you explain
final int UNKNOWN = -1;
Why final? Why UNKNOWN? Why -1? I understand int!

I think I also understand the use of myFlag and UNKNOWN in mouseDragged() and mousePressed().

Q2
The order of the elements in your Class (dragX, dragY, diam) is not the same as the order they are listed in the Constructor (diam, dragX, dragY). Does the order matter in Class? Does the order matter in Constructor?

1 Like