Change shape when changing directions

I am working through “Coding Art” and there is an extra task I am not able to solve until now. I am really a beginner and this task seems quite hard without coding experience at all.

I have Particles moving in a circle and changing directions when their distance from center greater than 150:

//reserve memory for 4000 particles
Particle[] particles = new Particle [40];

void setup() {
  size(600, 600);
  smooth();
  noStroke();
  
  //loop through all 4000 particles an initialize
  for (int i = 0; i < 40; i++) {
    particles[i] = new Particle();
  }
}



void draw() {
  //dark background
  background(35, 27, 105);
  
  //always draw from center of canvas
  translate(width/2, height/2);
  
  //loop through all particles
  for (Particle p : particles) {
    //change position and draw particle
    p.move();
    p.show();
  }
}

//create new class for our particle
class Particle {
  float x, y, size, directionX, directionY, shape;
  
  //initialize (called 'constructor')
  public Particle() {
    this.size = random(1, 17);
    this.directionX = random(-1, 1);
    this.directionY = random(-1, 1);
  }
  
  //function to move the particle position in direction
  public void move() {
    //calculate distance from center
    if (dist(this.x, this.y, 0, 0) > 150) {
      //create position and new random target position
      PVector position = new PVector(this.x, this.y);
      PVector target = new PVector(random(-250, 250), random(-250, 250));
      //calculate direction vecotr betwenn current and target position
      PVector direction = PVector.sub(target, position);
      //divide direction by 300 to make the steps small
      direction.div(300);
      //set new direction for the particle
      directionX = direction.x;
      directionY = direction.y;
    }
    this.x += directionX;
    this.y += directionY;
  }
  
  //draw the particle on the Processing canvas
  public void show() {
    //set individual particle color
    fill(195, 215, 112);
    //draw particle shape
    ellipse(this.x, this.y, this.size, this.size);
    //draw circle
    noFill();
    stroke(250);
    ellipse(0, 0, 310, 310);
    noStroke();
  }
}

And the task is to change the ellipses to a rectangle when they change directions. It’s mentioned that it must be done in the show() function. But I have no clue how to do it.

It’s clear to me that I have to do something like:

  • if direction changes
  • then change the shape to rectangle.

But how do I know, when direction has changed?

I think it must something be like

  • store the direction information of each particle in an array
  • when a direction changes, change the shape in the show function.

Is this path going in the right direction? Grateful for any suggestions how to solve this.
Thanks in advance.

1 Like

store a boolean metCircle = false; in the class

When particle hits the circle set it to true individually

Evaluate the variable metCircle to decide if you draw a circle or a rectangle

It’s pretty easy actually

You’ve got this check inside method Particle::move():

So it’s inside that if () block that you should make the decision to switch to either circle() or square().

As @Chrisir already advised, add an extra boolean field to your class Particle.

Inside your Particle::show() method invoke square() when that boolean is true, otherwise invoke circle().

Here’s a refactor I did to your code:

/**
 * Circle/Square Within Big Circle (v1.0.1)
 * by Marina_Kdot (2021-Dec-27)
 * mod GoToLoop
 *
 * Discourse.Processing.org/t/change-shape-when-changing-directions/34315/3
 */

final Particle[] particles = new Particle[40];
final PApplet p = this;

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

  rectMode(CENTER);
  strokeWeight(1.5);

  for (int i = 0; i < particles.length; particles[i++] = new Particle());
}

void draw() {
  background(35, 27, 105);
  translate(width >> 1, height >> 1);

  noStroke();
  fill(195, 215, 112);
  for (final Particle p : particles)  p.move().show();

  stroke(250);
  noFill();
  circle(0, 0, height >> 1);
}

class Particle {
  final PVector pos, dir;
  final int diam;
  boolean isSquare;

  Particle() {
    diam = (int) random(4, 20);
    pos = new PVector(diam, diam);
    dir = PVector.random2D(p);
  }

  Particle move() {
    final int h = height;

    if (sq(pos.x) + sq(pos.y) > sq(h - diam*2 >> 2)) {
      isSquare ^= true;
      pos.add(PVector.random2D(dir, p).mult(h / 3).sub(pos).div(h >> 1));
    }

    pos.add(dir);

    return this;
  }

  Particle show() {
    if (isSquare)  square(pos.x, pos.y, diam);
    else           circle(pos.x, pos.y, diam);

    return this;
  }
}
2 Likes

Thanks a lot for your fast help.

@Chrisir your input helped a lot and I added the boolean and checked it in the move().

public void move() {
    //calculate distance from center
    if (dist(this.x, this.y, 0, 0) >= 150) {
      //check value of metCircle boolean and change it
      if (metCircle == false) {
        metCircle = true;
      } else {
        metCircle = false;
      };

In the show() I added this if statement

 //draw particle shape
    if (metCircle == true) {
      ellipse(this.x, this.y, this.size, this.size);
    } else {
      rect(this.x, this.y, this.size, this.size);
    }

For sure this is not the most beautiful code. But it works for the first time :star_struck:

@GoToLoop Your solution looks so clean and I like it a lot. But unfortunately I haven’t covered all the things you’re using in it right now. I see huge possibilities to grow :grinning_face_with_smiling_eyes:

Thanks to both of you.

2 Likes

short form

if( ! metCircle) {

! means “not”


short form

if (metCircle) {

1 Like

Thanks for this! Very helpful.

Meanwhile I replaced the whole if statement where I checked metCircle with this expression:

metCircle = !metCircle;

As I understand, whatever metCircle is, this expression will change it to the opposite. Makes it nice and short. But writing the if/else statement was very helpful to understand what’s happening.

2 Likes

it is not necessary to use “this.” in the class.

(this is only necessary when you pass a variable in the constructor which has the same name as the class’s variables (to distinguish them), but not in your code)

2 Likes

Hi everyone. I actually didn’t get the idea of metCircle, I’ve solved this just by adding conditional in the ‘show’ function:

public void show() {

[…]

if (dist(this.x, this.y, 0, 0) < 245) {
  ellipse(this.x, this.y, this.size, this.size);
  
} else {
  rect(this.x, this.y, this.size, this.size);
}

it may be not the best solution, but it works