Send value to a object

Hello everybody. I`ve a problem:

I`ve a array of ellipse Objects. Every object has his variable of size in the constructor. In a second screen, via controlP5, a slider that change the size of every ellipse. What i want is change the size of an ellipse object when isClicked is true, and in that particular object, and store that value. But i cant, and i dont know exaclty why. I think that when i change the size in the constructor every object take the same value.

here the code, sorry for my very bad english, hope you understand:

(in resume: click the object, change it value, store the value. click in another object, and change it value (different of object 1)…etc.)

import controlP5.*;

ArrayList<Sphere>s;
PWindow controller;


void settings() {
  size(500, 500, P3D);
}


void setup() {
  controller = new PWindow();

  s = new ArrayList<Sphere>();
  s.add(new Sphere(new PVector(random(width), random(height)), 255, 50, 0));
}

void draw() {
  background(0);
  pushMatrix();
  select();

  for (Sphere s : s) {
    s.display();
    s.isOver(mouseX, mouseY);
  }
  popMatrix();
}

void select() {
  for (Sphere s : s) {
    if (s.isClick) {
      println(s.id, "HOLA");
      s.c = 25;
      println("");
    }
  }
}

void mousePressed() {

  if (mouseButton==RIGHT) s.add(new Sphere(new PVector(mouseX, mouseY), 255, 50, s.size()+1));

  for (Sphere s : s) {
    if (mouseButton==LEFT && s.over) {
      s.isClick = true;
    } else {
      s.isClick = false;
    }
  }
}

class Sphere {

  float c, size;
  float x, y;
  ArrayList<PVector> p = new ArrayList<PVector>();
  boolean over = false;
  boolean isClick = false;
  int id;
  int initialValue = 50;

  Sphere(PVector pos, float _color, float _size, int _id) {
    p.add(pos);
    c = _color;
    size = _size;
    id = _id;
  }

  void display() {
    for (PVector pos : p) {
      pushMatrix();
      translate(pos.x, pos.y);
      fill(c);  
      ellipse(0, 0, size, size);
      popMatrix();
    }
  }

  boolean isOver(float px, float py) {
    ellipseMode(RADIUS);
    for (PVector pos : p) {
      float d = dist(px, py, pos.x, pos.y);
      if (d < size) {
        over = true;
        c = 150;
        return true;
      } else {
        over = false;
        c = 255;
        return false;
      }
    }
    return false;
  }
}
public class PWindow extends PApplet {  

  PWindow() {
    super();
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
  }

  ControlP5 cp5;

  int vertices = 50;
  float ss;


  Slider abc;


  void settings() {
    size(500, 250, P2D);
  }

  void setup() {
    cp5 = new ControlP5(this);
    background(0);


    cp5.addSlider("vertices")
      .setPosition(25, 50)
      .setSize(200, 20)
      .setRange(0, 50)
      ;
  }

  void draw() {
    background(0);

    for (int i = s.size()-1; i >= 0; i--) {
      Sphere obj = s.get(i); 
      ss = vertices;
      
      if (obj.isClick==true) {
        fill(255);
        stroke(255);
        textSize(13);
        text(i, width/2, 150);
        println(i);
        obj.size = vertices;
      }
    }
  }
  
}
1 Like

Okay, separate issues.

  1. Do you know how to act on slider events in your controller window, e.g. see the ControlP5slider example. So for a very simple example – if you have a global variable in your main sketch

    float radius;
    

    …and named your slider “vertices”, then one of several ways you can get the value is to define a callback function with the same name that you gave your slider – the function will be automatically called when you move the slider, updating the global variable:

    void vertices(float theRadius) {
      radius = theRadius;
    }
    
  2. Now that you can see it working, you need to think about some design issues: where should drawing choices happen, in what order should objects be drawn, in what order should clicks be checked, how to display mouseover and click state in the drawing, etc. These things are creating lots of small issues that make your sketch a bit difficult to interact with and understand.

Study this simplified example. Change DESELECTOTHERS to true to only select one object at a time.

import controlP5.*;

ArrayList<Sphere> s;
PWindow controller;
float radius;
boolean DESELECTOTHERS = false;


void settings() {
  size(500, 500, P2D);
}

void setup() {
  controller = new PWindow();
  s = setupSpheres();
}

// make setup logic reset-able
ArrayList<Sphere> setupSpheres() {
  ArrayList<Sphere> newS = new ArrayList<Sphere>();
  for (int i=0; i<10; i++) {
    newS.add(new Sphere(new PVector(random(width), random(height)), 255, random(25, 100), i));
  }
  // pre-select the first object
  newS.get(1).isClick = true;
  return newS;
}

void draw() {
  background(0);
  pushMatrix();

  // if you want to click overlapping things
  // in visual order (select topmost first),
  // then you need to either draw backward
  // and check for clicks forward -- or vice-versa.
  // This is the backwards loop from:
  //   processing.org/reference/ArrayList.html
  for (int i = s.size() - 1; i >= 0; i--) {

    // don't shadow your list name with the item name s:s
    Sphere sp = s.get(i);

    // don't store things that change every frame
    // in object variables -- get them live
    boolean over = sp.isOver(mouseX, mouseY);
    // do store things that happened in the past
    boolean clicked = sp.isClick;

    // move your situational drawing decisions out of
    // the object -- detect the situation, then request a
    // drawing configuration
    if (clicked && over) {
      sp.display(color(255, 0, 0), 5);
    } else if (clicked) {
      sp.display(color(255, 192, 192), 1);
    } else if (over) {
      sp.display(color(192), 5);
    } else {
      sp.display(color(255), 1);
    }
  }
  popMatrix();
}

void mousePressed() {
  if (mouseButton==RIGHT) {
    s.add(new Sphere(new PVector(mouseX, mouseY), 255, 50, s.size()+1));
  }

  // don't shadow your list name with the item name s:s
  for (Sphere sp : s) { 
    if (mouseButton==LEFT && sp.isOver(mouseX, mouseY)) {

      // toggle the click state on-off by boolean to not-itself
      sp.isClick = !sp.isClick;

      // optionally deselect others on a new selection
      if(DESELECTOTHERS == true){
        for (Sphere newsp : s){
          if(newsp!=sp) newsp.isClick = false;
        }
      }

      // only click the first object found if they overlap
      // -- then bail out of the loop and don't check for others 
      break;
    }
  }
}

class Sphere {
  float c, size;
  float x, y;
  PVector p = new PVector();
  // clicks yes, mouseOver-state no
  boolean isClick = false;
  int id;
  int initialValue = 50;

  Sphere(PVector pos, float _color, float _size, int _id) {
    p.add(pos);
    c = _color;
    size = _size;
    id = _id;
  }

  // add parameters to display.
  // if you want to simultaneously indicate two separate states,
  // like isOver and wasClicked, consider two visual parameters
  // or use alpha / transparency, or mix colors
  void display(int fillColor, float strokeWeight) {
    pushMatrix();
    pushStyle();
    translate(p.x, p.y);
    // no application state logic here -- just how to draw
    fill(fillColor);
    strokeWeight(strokeWeight);
    ellipse(0, 0, size, size);
    popStyle();
    popMatrix();
  }

  // no drawing here -- just an answer to the question
  // is it over?
  boolean isOver(float px, float py) {
    ellipseMode(RADIUS);
    float d = dist(px, py, p.x, p.y);
    if (d < size) {
      return true;
    }
    return false;
  }
}

public class PWindow extends PApplet {  

  PWindow() {
    super();
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
  }

  ControlP5 cp5;
  Slider abc;

  void settings() {
    size(500, 250, P2D);
  }

  void setup() {
    cp5 = new ControlP5(this);
    background(0);
    cp5.addSlider("circle_size")
      .setPosition(25, 50)
      .setSize(200, 20)
      .setRange(0, 200)
      // currently the initial state of your controller will
      // propogate to your selection -- so if you initialize
      // it at 0 then the first selected object will be 0.
      // instead let's start at 100
      .setValue(100)
      ;
    cp5.addButton("resetButton")
      .setPosition(25, 100)
      // use a meaningful function name, and a shorter label if
      // clear code and clear UI are different
      .setLabel("reset")
      ;
  }

  void draw() {
    background(0);
  }

  // cp5 callback for slider
  // transmit slider callback to currently selected object
  // -- cp5 automatically tries to call a function with the
  // same name as your control whenever you interact with
  // the control. If you name your control "abcdefg", then
  // one way to catch its events is with `void abcdefg()`
  void circle_size(float theSize) {
    for (Sphere sp : s) {
      if (sp.isClick) {
        sp.size = theSize;
      }
    }
  }

  // cp5 callback for button
  void resetButton() {
    s = setupSpheres();
  }
}