CodeTrain Circlepacking with random sticky colors

Hi there - very new to Processing, so be gentle :slight_smile:
Starting with some coding train tutorials and modding a bit along the way, below code is an example of that.
I want to fill the circles with colors from a palette which I defined in an array. Kinda figured it out except I dont want the colors to change all the time while the shape is being filled up, but rather a shape should be born with one color and stick with that. Any guidance appreciated.

best
Chr

// Daniel Shiffman
// http://codingtra.in
// http://patreon.com/codingtrain
// Code for: https://youtu.be/QHEQuoIKgNE

float myAlpha = 255;
color c1 = color(1, 33, 83, myAlpha);
color c2 = color(0, 148, 255, myAlpha);
color c3 = color(0, 255, 255, myAlpha);
color c4 = color(255, 200, 0, myAlpha);
color c5 = color(255, 99, 0, myAlpha);
color c6 = color(255, 0, 130, myAlpha);
color[] colors = {c1, c2, c3, c4, c5, c6};

ArrayList<Circle> circles;
ArrayList<PVector> spots;
PImage img;

color palFill(){
  color mycol = colors[int(random(0,6))];
  return mycol;
}


void setup() {
  size(1920, 1080);
  spots = new ArrayList<PVector>();
  img = loadImage("image.png");
  img.loadPixels();
  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++) {
      int index = x + y * img.width;
      color c = img.pixels[index];
      float b = brightness(c);
      if (b > 1) {
        spots.add(new PVector(x,y));
      }
      
    } 
  }
  circles = new ArrayList<Circle>();
}

void draw() {
  background(255);
  randomSeed(448);

  int total = 10;
  int count = 0;
  int attempts = 0;

  while (count <  total) {
    Circle newC = newCircle();
    if (newC != null) {
      circles.add(newC);
      count++;
    }
    attempts++;
    if (attempts > 10000) {
      noLoop();
      println("FINISHED");
      break;
    } 
  }
  for (Circle c : circles) {
    float mdist = dist(mouseX, mouseY, c.x, c.y);
    if(mdist<100){
    }
  }

  for (Circle c : circles) {
    if (c.growing) {
      if (c.edges()) {
        c.growing = false;
      } else {
        for (Circle other : circles) {
          if (c != other) {
            float d = dist(c.x, c.y, other.x, other.y);
            if (d - 1 < c.r + other.r) {
              c.growing = false;
              break;
            }
          }
        }
      }
    }
    c.show();
    c.grow();
    c.colorize(palFill());
  }
}

Circle newCircle() {
  int r = int(random(0,spots.size()));
  PVector spot = spots.get(r);
  float x = spot.x;
  float y = spot.y;

  boolean valid = true;
  for (Circle c : circles) {
    float d = dist(x, y, c.x, c.y);
    if (d-3 < c.r) {
      valid = false;
      break;
    }
  }
  if (valid) {
    return new Circle(x, y);
  } else {
    return null;
  }
}

Hello there, welcome to this forum :slight_smile:
We are always most gentle and circumspect. Always !

I dient scrutinize your code in detail, but I think the issue is the same as with your x/y positions.
If you have many circles, you need to maintain an individual variable for their values do. Which is why you maintain a second ArrayList named ‘spots’.

Same goes for the colors, yet either there is only on color that you set from your set of 6.
Another reason might be that you call that random choice for the color in draw, so it is well… changed every frame.

“Technically” each circle must have its own position and color (an arrayList) and you should set its color at creation or based on an event (like find new random colors when the mouse is clicked) but not every frame.

thx Hyperion65 - got it working by using the approach you suggested, involved changing code in the circle class as well as the circlepacking one.

// Daniel Shiffman
// http://codingtra.in
// http://patreon.com/codingtrain
// Code for: https://youtu.be/QHEQuoIKgNE


float myAlpha = 255;
color c1 = color(1, 33, 83, myAlpha);
color c2 = color(0, 148, 255, myAlpha);
color c3 = color(0, 255, 255, myAlpha);
color c4 = color(255, 200, 0, myAlpha);
color c5 = color(255, 99, 0, myAlpha);
color c6 = color(255, 0, 130, myAlpha);
color[] palette = {c1, c2, c3, c4, c5, c6};

ArrayList<Circle> circles;
ArrayList<PVector> spots;
PImage img;

void setup() {
  size(50,50);
  spots = new ArrayList<PVector>();
  img = loadImage("image.png");
  img.loadPixels();
  int iw = img.width;
  int ih = img.height;
  frame.resize(400, 400);
  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++) {
      int index = x + y * img.width;
      color c = img.pixels[index];
      float b = brightness(c);
      if (b > 1) {
        spots.add(new PVector(x,y));
      }
      
    } 
  }
  circles = new ArrayList<Circle>();
}

void draw() {
  background(255);

  int total = 4;
  int count = 0;
  int attempts = 0;

  while (count <  total) {
    Circle newC = newCircle();
    if (newC != null) {
      circles.add(newC);
      count++;
    }
    attempts++;
    if (attempts > 10000) {
      noLoop();
      println("FINISHED");
      break;
    } 
  }

  for (Circle c : circles) {
    if (c.growing) {
      if (c.edges()) {
        c.growing = false;
      } else {
        for (Circle other : circles) {
          if (c != other) {
            float d = dist(c.x, c.y, other.x, other.y);
            if (d - 1 < c.r + other.r) {
              c.growing = false;
              break;
            }
          }
        }
      }
    }
    c.show();
    c.grow();
  }
}

Circle newCircle() {
  int r = int(random(0,spots.size()));
  int cr = int(random(0,6));
  PVector spot = spots.get(r);
  float x = spot.x;
  float y = spot.y;
  color cirCol = palette[cr];

  boolean valid = true;
  for (Circle c : circles) {
    float d = dist(x, y, c.x, c.y);
    if (d-3 < c.r) {
      valid = false;
      break;
    }
  }
  if (valid) {
    return new Circle(x, y, cirCol);
  } else {
    return null;
  }
}

// Daniel Shiffman
// http://codingtra.in
// http://patreon.com/codingtrain
// Code for: https://youtu.be/QHEQuoIKgNE

class Circle {
  float x;
  float y;
  float r;
  color cirCol;
  boolean growing = true;

  Circle(float x_, float y_, color cirCol_) {
    x = x_;
    y = y_;
    cirCol = cirCol_;
    r = random(0.1,1);
  }

  void grow() {
    if (growing) {
      r = r + 0.3;
    }
  }

  boolean edges() {
    return (x + r > width || x -  r < 0 || y + r > height || y -r < 0);
  }

  void show() {
    noStroke();
    ellipse(x, y, r*2, r*2);
    fill(cirCol);
  }
}