Convert to array; then variable i does not exist error message

I converted this from a single instance of each object to implement 2 arrays of multiple ball objects + donut objects.

I get the error message the variable i does not exist.
Both arrays have been initialized in setup().
I tried commenting out one of the arrays to see if there was some kind of conflict but got the same message.
It’s probably a very simple oversight on my part but I can’t seem to locate the problem origin.

Any help is most appreciated. :slight_smile:

Ball [] balls = new Ball [3];
Donut [] donuts = new Donut [3];

color backgroundColor = 255; 

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

  for (int i = 0; i < balls.length; i++) {
    balls[i] = new Ball();
  }
  for (int i = 0; i < donuts.length; i++) {
   donuts[i] = new Donut();
  }
}
void draw() {
  background(backgroundColor);

  for (int i = 0; i < balls.length; i++);{
   balls[i].display();
   balls[i].move();
   balls[i].bounce();
   balls[i].intersect();
  }

  for (int i = 0; i < donuts.length; i++);{
    donuts[i].display();
    donuts[i].move();
    donuts[i].bounce();
    donuts[i].intersect();
  }
}
//BALL CLASS //////////////////////////////////////////////////////////////////// 

class Ball {
  int x;
  int y;
  int r;
  int speed;

  boolean isBlue=false; 

  boolean firstTime=true; // for background

  Ball() {
    x = 0;
    y = height/2;
    r = 50;
    speed = 5;
  }

  void display() {
    //noFill();
    if (isBlue){
    fill(255, 0, 0, 50);
    }
    strokeWeight(3);
    ellipse(x + r/2, y, r, r);
  }
  void move() {
    x = x + speed;
  }
  void bounce() {
    if ((x >= width - r)||(x <= 0)) {
      speed = speed *-1;
    }
  }
  void intersect() {
    float distance = dist(x, y, donuts.x, donuts.y);
    if (distance < r + donuts.r) {
      if (firstTime){
        backgroundColor = color(random(255));
      }
      isBlue=true;
      firstTime=false;
    } else {
      firstTime=true;
    }
  }
}
//DONUT CLASS //////////////////////////////////////////////////////////////////// 

class Donut {
  int x;
  float y;
  int r;
  float speed;

  boolean isRed=false; 

  Donut() {
    x = width/2;
    y = 50;
    r = 50;
    speed = random(1, 5);
  }
  void display() {
    noFill();
    if (isRed){ 
     fill(0, 0, 255, 50);
    }
    strokeWeight(3);
    ellipse(x, y, r, r);
    ellipse(x, y, r*2, r*2);
  }
  void move() {
    y = y + speed;
  }
  void bounce() {
    if ((y >= height - r)||(y <= 50)) {
      speed = speed *-1;
    }
  }
  void intersect() {
    float distance = dist(x, y, balls.x, balls.y);
    if (distance < r + balls.r) {
    isRed=true;
    }
  }
}
1 Like
for (int i = 0; i < balls.length; i++);
{

The semicolon ; prematurely ends the for () command! :warning:

2 Likes

Oh of course! Thank you @GoToLoop!

But now the x variable is not being recognized in the intersect() function.
When I converted to array I changed:

this line:

float distance = dist(x, y, d.x, d.y);

to this line:

float distance = dist(x, y, donuts.x, donuts.y);

I think this is the problem area. I need to refer to the name, yes? to connect the distance relationship?

I have been searching on web to try to find solution to this but so far unsuccessfully.

Adding the for (int = 0… and array still doesn’t work in the intersect function.
How do I set up for each object in array to check for distance?

void intersect() {
    for (int i = 0; i<donuts.length; i++) { //should I add this to count all of the donuts in the array in order to check distance for each?
      
float distance = dist(x, y, donuts.x, donuts.y);

      if (distance < r + donuts.r) {
        isRed=true;
      }
    }
  }

Hi there!
Your intersect method in Ball has no idea of which donut.x or donut.y it is intersecting a good idea would be to write getX and getY method for the donut to simplify this do we can squeeze both values in into an PVector and return the PVector, then the Ball interesct() method will accept these as parameters and compare !
Here’s the code:

For the donut.

PVector donutPos(){
     return new PVector(x,y);
}

For the ball:

void intersect(PVector donuts) {
    float distance = dist(x, y, donuts.x, donuts.y);
    if (distance < r + donuts.r) {
      if (firstTime){
        backgroundColor = color(random(255));
      }
      isBlue=true;
      firstTime=false;
    } else {
      firstTime=true;
    }
  }
}

Loop in draw:

 for (int i = 0; i < balls.length; i++);{
   balls[i].display();
   balls[i].move();
   balls[i].bounce();
   balls[i].intersect( donuts[i].donutPos() );
   donuts[i].display();
   donuts[i].move();
   donuts[i].bounce();
   donuts[i].intersect( balls[i].ballPos() );
  }

You can write the same the intersect method and ballPos() method like the donutPos(). Also as your arrays of objects are the same size you can iterate through all of them in one loop !

Any questions let me know!

2 Likes

Your intersect() methods need a parameter of the datatype it’s gonna compare to. :cookie:

For example in the class Donut, its intersect() is supposed to compare to a Ball object. :softball:

boolean intersect(final Ball b) {
  final int rad = b.r >> 1;
  return sq(b.x + rad - x) + sq(b.y + rad - y) < sq(r + rad);
}

As another example, take a look at the method Ball::colliding() from the online sketch below: :see_no_evil:
Studio.ProcessingTogether.com/sp/pad/export/ro.9qPrLGrYGkr2o

1 Like

Thank you @InferNova for your response!! :slightly_smiling_face:

The code below includes your suggestions. However, I’m not sure about the sequence as the code won’t run.

I am new to coding so am still at the stage of figuring out sequencing and flow of a program.

Would you be able to take a look and see where I’ve gone awry?

////////////////////////////////

Ball [] balls = new Ball [3];
Donut [] donuts = new Donut [3];

color backgroundColor = 255; 

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

  for (int i = 0; i < balls.length; i++) {
    balls[i] = new Ball();
  }
  for (int i = 0; i < donuts.length; i++) {
   donuts[i] = new Donut();
  }
}
void draw() {
  background(backgroundColor);

  for (int i = 0; i < balls.length; i++){
   balls[i].display();
   balls[i].move();
   balls[i].bounce();
   balls[i].intersect(donuts[i].donutPos());
  }

  for (int i = 0; i < donuts.length; i++){
    donuts[i].display();
    donuts[i].move();
    donuts[i].bounce();
    donuts[i].intersect(balls[i].ballPos());
  }
}
//Ball Class/////////////////////////////////

class Ball {
  int x;
  int y;
  int r;
  int speed;

  boolean isBlue=false; 

  boolean firstTime=true; // for background

  Ball() {
    x = 0;
    y = height/2;
    r = 50;
    speed = 5;
  }

  void display() {
    //noFill();
    if (isBlue){
    fill(255, 0, 0, 50);
    }
    strokeWeight(3);
    ellipse(x + r/2, y, r, r);
  }
  void move() {
    x = x + speed;
  }
  void bounce() {
    if ((x >= width - r)||(x <= 0)) {
      speed = speed *-1;
    }
  }
  
  PVector ballPos() {
    return new PVector(x, y);
  }
  
  void intersect(PVector donuts) {
    float distance = dist(x, y, donuts.x, donuts.y);
    if (distance < r + donuts.r) {
      if (firstTime){
        backgroundColor = color(random(255));
      }
      isBlue=true;
      firstTime=false;
    } else {
      firstTime=true;
    }
  }
}

//Donut Class/////////////////////////////////

class Donut {
  int x;
  float y;
  int r;
  float speed;

  boolean isRed=false; 

  Donut() {
    x = width/2;
    y = 50;
    r = 50;
    speed = random(1, 5);
  }
  void display() {
    noFill();
    if (isRed) { 
      fill(0, 0, 255, 50);
    }
    strokeWeight(3);
    ellipse(x, y, r, r);
    ellipse(x, y, r*2, r*2);
  }
  void move() {
    y = y + speed;
  }
  void bounce() {
    if ((y >= height - r)||(y <= 50)) {
      speed = speed *-1;
    }
  }
  PVector donutPos() {
    return new PVector(x, y);
  }

  void intersect() {
    float distance = dist(x, y, balls.x, balls.y);

    if (distance < r + balls.r) {
      isRed=true;
    }
  }
}

Thank you @GoToLoop for your response! As I am a novice coder it is interesting to see a variety of solutions!!

Hi there!
@debxyz. No problem I can help but before I post up the code, few issues I wanted to point with yours ( for your learning of course! ) in your intersection() methods you assume the size of the objects working with

What we are passing into that method is only a PVector which only holds two floats an x and a y ( these can be whatever we want them to be but conventionally works well for 2d objects) therefore the computer has no clue what a donuts.r is.

The problem with this is that you are changing the value isRed but your are not setting it off to change the value held within the class but only within the method. To fix this all you can do is return the variable which “spills out” the value to the class so the value of the variable within the class can be modified.
Overall that all the problems you had, it is important to take on a mindset while coding that the computers knows nothing ! absolutely zero ! you have to tell it everything.

Anyways, that it here’s the code:


Ball [] balls = new Ball [3];
Donut [] donuts = new Donut [3];

color backgroundColor = 255; 

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

  for (int i = 0; i < balls.length; i++) {
    balls[i] = new Ball();
  }
  for (int i = 0; i < donuts.length; i++) {
    donuts[i] = new Donut();
  }
}
void draw() {
  background(backgroundColor);

  for (int i = 0; i < balls.length; i++) {
    balls[i].display();
    donuts[i].display();
    balls[i].move();
    donuts[i].move();
    balls[i].bounce();
    donuts[i].bounce();
    balls[i].intersect(donuts[i].donutPos(), donuts[i].getSize());
    donuts[i].intersect(balls[i].ballPos(), balls[i].getSize());
  }
}
//Ball Class/////////////////////////////////

class Ball {
  int x;
  int y;
  int r;
  int speed;

  boolean isBlue=false; 

  boolean firstTime=true; // for background

  Ball() {
    x = 0;
    y = height/2;
    r = 50;
    speed = 5;
  }

  void display() {
    //noFill();
    if (isBlue) fill(0, 0, 255);
    else fill(255, 255, 0);
    strokeWeight(3);
    ellipse(x + r/2, y, r, r);
  }
  void move() {
    x = x + speed;
  }
  void bounce() {
    if ((x >= width - r)||(x <= 0)) {
      speed = speed *-1;
    }
  }

  PVector ballPos() {
    return new PVector(x, y);
  }
  float getSize() {
    return r;
  }
  boolean intersect(PVector donuts, float donutRadius ) {
    float distance = dist(x, y, donuts.x, donuts.y);
    if (distance < r + donutRadius) return isBlue = true;
    return isBlue = false;
  }
}

//Donut Class/////////////////////////////////

class Donut {
  int x;
  float y;
  int r;
  float speed;

  boolean isRed=false; 

  Donut() {
    x = width/2;
    y = 50;
    r = 50;
    speed = random(1, 5);
  }
  void display() {
    if (isRed) fill(255, 0, 0);
    else fill(0, 255, 0);
    strokeWeight(3);
    ellipse(x, y, r, r);
    ellipse(x, y, r*2, r*2);
  }
  void move() {
    y = y + speed;
  }
  void bounce() {
    if ((y >= height - r)||(y <= 50)) {
      speed = speed *-1;
    }
  }
  PVector donutPos() {
    return new PVector(x, y);
  }
  float getSize() {
    return r;
  }
  boolean intersect(PVector balls, float ballRadius) {
    float distance = dist(x, y, balls.x, balls.y);
    if (distance < r + ballRadius) return isRed = true;
    return isRed = false;
  }
}
2 Likes

Thank you @InferNova!! :joy:

This is the intended result!

One final question. To access items in an array and have them interact I must convert my object in the CLASS code to use PVector? (Not the x,y coordinates?)

1 Like

@debxyz
No problem!
To have them interact you can keep it as it is for example here interact(PVector donuts) this would have been as valid interact( float x , float y ) I just did it to have less clutter ! But either way is completely valid again PVector is just an object that can store an x and a y and bunch of other stuff !

@InferNova I’m sorry to keep asking questions, but it sounds like you’re saying I can write this code using PVector (which is cleaner code) ~ or ~ using float x, float y code (which is longer code and has more clutter)?

Is it possible to show the longer code (NOT using the PVector)? Just so I can compare to learn what the difference is?

Works the same just we are not wrapping the values in a PVector to store it inside it. Also I put your move and bounce methods in display. As these work coherently with one another you can have one method calling them all at the end as this is more efficient and less clutter is generated.

Here it is:



Ball [] balls = new Ball [2];
Donut [] donuts = new Donut [2];

color backgroundColor = 255; 

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

  for (int i = 0; i < balls.length; i++) {
    balls[i] = new Ball();
  }
  for (int i = 0; i < donuts.length; i++) {
    donuts[i] = new Donut();
  }
}
void draw() {
  background(backgroundColor);

  for (int i = 0; i < balls.length; i++) {
    balls[i].display();
    donuts[i].display();
    balls[i].intersect(donuts[i].getX(), donuts[i].getY(), donuts[i].getSize());
    donuts[i].intersect(balls[i].getX(), balls[i].getY(), balls[i].getSize());
  }
}
//Ball Class/////////////////////////////////

class Ball {
  int x;
  int y;
  int r;
  int speed;

  boolean isBlue=false; 

  boolean firstTime=true; // for background

  Ball() {
    x = (int)random(1 , width/2);
    y = height/2;
    r = 50;
    speed = 5;
  }

  void display() {
    //noFill();
    if (isBlue) fill(0, 0, 255);
    else fill(255, 255, 0);
    strokeWeight(3);
    ellipse(x + r/2, y, r, r);
    move();
  }
  void move() {
    x = x + speed;
    bounce();
  }
  void bounce() {
    if ((x >= width - r)||(x <= 0)) {
      speed = speed *-1;
    }
  }

  float getX() {
    return x;
  }
  float getY() {
    return y;
  }
  float getSize() {
    return r;
  }
  boolean intersect(float donutsX, float donutsY, float donutRadius ) {
    float distance = dist(x, y, donutsX, donutsY);
    if (distance < r + donutRadius) return isBlue = true;
    return isBlue = false;
  }
}

//Donut Class/////////////////////////////////

class Donut {
  int x;
  float y;
  int r;
  float speed;

  boolean isRed=false; 

  Donut() {
    x = width/2;
    y = 50;
    r = 50;
    speed = random(1, 5);
  }
  void display() {
    if (isRed) fill(255, 0, 0);
    else fill(0, 255, 0);
    strokeWeight(3);
    ellipse(x, y, r, r);
    ellipse(x, y, r*2, r*2);
    move();
  }
  void move() {
    y = y + speed;
    bounce();
  }
  void bounce() {
    if ((y >= height - r)||(y <= 50)) {
      speed = speed *-1;
    }
  }
  float getX() {
    return x;
  }
  float getY() {
    return y;
  }
  float getSize() {
    return r;
  }
  boolean intersect(float ballX, float ballY, float ballRadius) {
    float distance = dist(x, y, ballX, ballY);
    if (distance < r + ballRadius) return isRed = true;
    return isRed = false;
  }
}
2 Likes

Thank you so much for this great explanation @InferNova!! This is tremendously helpful. :joy::joy::joy:
And thank you for introducing the PVector.

1 Like