How do I make expanding circles react on contact?

Hi, I've made a sketch of circles that grow (some which then disappear) when you click the mouse. What I'm trying to make happen is every time an expanding circle touches another a new expanding circle will spawn on that point.

I've tried doing this using a simple hit test, but obviously it doesn't work as well aesthetically because the hit test runs on squares. I read that the best way to do it is using "cart to polar" (?) but I just don't know what to do concerning this.

Any help on making this work would be much appreciated :)

Here is the code I've got so far (left click creates circles that disappear as they grow, right click creates circles that will just keep on growing without fading, and spacebar will clear the page):

ArrayList circles = new ArrayList();

void setup() {
  size(1280, 720, P2D);
  smooth();
}

void draw(){
  background(50);

  for (int i=0; i<circles.size(); i++) {
    ExpandingCircle ec = (ExpandingCircle) circles.get(i);
    ec.update();
    ec.display();
    if (ec.transparency <= 0) { circles.remove(i); } // remove invisible circles
  }
}

class ExpandingCircle {
  int x,y;
  float radius;
  color c;
  boolean transparencyOn;
  int transparency;

  ExpandingCircle(int x, int y, boolean transparencyOn) {
    this.x = x;
    this.y = y;
    this.transparencyOn = transparencyOn;
    c = color(random(150, 255),random(150, 255),random(150, 255), 100);
    //c = color(random(255), 100);
    //c = color(255, 150);
    transparency = 255;
  }
  void update() {
    radius++;
    if (transparencyOn && radius >= 50 && transparency > 0) { transparency--; }
  }

  void display() {
    noStroke();
    fill(c,transparency);
    ellipse(x,y,radius,radius);
  }
}

void mousePressed()
{
  if (mouseButton == RIGHT) { circles.add(new ExpandingCircle(mouseX,mouseY,false));
  } else { circles.add(new ExpandingCircle(mouseX,mouseY,true)); }

}

void keyPressed() {
  if (key == ' ') { circles.clear(); }
}

Answers

  • Can't you just use the distance between the center points of the circles? If that value is within some threshold of the sum of their radiuses, then the two circles are touching.

  • Perhaps most diff. part gonna be avoid triggering it more than once! :-SS

  • Yep, that's why I said "within some threshold" instead of "less than".

  • Even within a threshold, it's gonna be triggered many times @ 60 FPS me guess! (%)

  • That depends on what you use a threshold.

  • edited November 2014

    Hello ! I may will do something like that

    1) inside your circle-objects, create an arrayList that will register every already contacted circles.

    2) still inside your circle-object, create a function "hittest" with a circle-object as parameter. Inside that function, check the distance between the center of the circle and the center of the other circle. If the distance is less than the sum of the radius of the two circle, then there is a collision.

    3-a) if you find a collision between 2 circles, loop on your arrayList to see if the collided-circle is already registred. If not, register it and create a new circle at the collision point. To get the position of the collision point. You need to get the angle from the center of your object to the other circle (you just have to use atan2 function to do it). Then the collision point will be there

    collisionX = cos(angle) * radius;
    collisionY = sin(angle) * radius;
    

    3-b) during the arrayList-loop, check the alpha of each registered circle. If a circle is transparent, remove it.

    That's all !

    If you do that, you will be sure that each circle can collide only one time with another circle (but can still collide the other non-collided yet circles)

    Good luck :)

  • edited November 2014

    Appending to what @tlecoz said above, another alternative for registering "touched pairs": O:-)

    • Every ExpandingCircle needs to have an extra id internal field.
    • It can be a regular int or even a char, since the latter can't be negative (unsigned) after all.
    • And in turn, the "sketch" needs a counter "global" field.
    • When instantiating new ExpandingCircle objects, pass ++counter as its extra argument and assign it as their id internal field.
    • Now every time 2 ExpandingCircle objects successfully collide, we also need to multiply their id values.
    • For example, if id #5 collided w/ id #3, total = 5 * 3 = 15.
    • Check out whether multiplied id total, in the case above 15, is already present in the "touched pairs" IntList w/ its method hasValue().
    • If it is so, ignore that collision. Otherwise create a new ExpandingCircle object w/ next ++counter id.
    • In case multiplied total isn't present, don't forget to append() it to the "touched pairs" IntList.
    • In short, a particular pair becomes sterile after 1 birth; but individually they can still breed w/ some1 else!
  • Hello GoToLoop ,

    I think your solution is a bit weird, at least for the first 100 circles because if the circle#2 touches the circle#3, then those 2 circles could nevers collide with circle#6. It's just an example but there are other possibilities.

    You can solve that easily : you just have to start your id by 1000 instead of 0. Then you have, in the worst case, one chance on a million to miss a collision.

  • @tlecoz, my rationale was a little too much ahead I agree! ~:>
    But it could happen w/ 3 ExpandingCircle objects create at the same time, w/ 2 of it near each other and another a little farther. Also w/ diff. growth speeds! 8-X

  • edited November 2014

    You just have to start your id by 1000 instead of 0.

    That ++counter would add 1 to counter 1st. And thus it'd never be 0 until overpassing its type capacity. :-B

  • Thanks so much for all the help guys! But I'm very new to this whole coding thing, as I really appreciate your advice but I don't actually know how to implement it.

    tlecoz, your three steps sound like just what I need to do! But where exactly is my circle-objects and how do I create an array list that registers already contacted circles? I'm not even sure how to let the circles know that they are touching.

    I'm sure some of this must be quite simple stuff, but again, please bare with a complete coding newbie :)

  • @GoToLoop : you can increment by one and start your index at 1000, it's not an opposite idea. I just say that instead of write that

    int counter; void setup(){ counter = 0; }

    you should write that

    int counter; void setup(){ counter = 1000; }

    @AlfieChillar : you must to try a little bit by yourself, look at the examples, look at the reference at "arrayList". If it still not working, send us your current code and we 'll look at it :)

  • edited November 2014

    int counter; void setup(){ counter = 0; }

    All Java fields got default initial values. An int is already 0! O:-)
    And ++counter would add 1 and return updated value! Hence 1st id = 1! :-bd

  • edited November 2014

    ??? I really think you don't understand what I mean....

    "All Java fields got default initial values. An int is already 0! "

    "And ++counter would add 1 and return updated value! Hence 1st id = 1! "

    .....Ok.......

    Do you think the universe will crash on itself if I assign 1000 to my Int in the setup function and then increment it using myInt++ or ++myInt ?

    Really, don't see / understand the problem. The default value of a Int is 0. Ok , I never said the contrary. Now is it possible to set his value to 1000 in the setup values ? - I bet it's possible -

    and then, is it possible to say "that int, greater or equal to 1000" would be our circle-id. The next circle-id would be 1001, and the next 1002, and so on ? - I bet it's possible too -

    If it's possible, then the "collision-ID " between circle1001 et circle1002 would be 1001x1002. Every other ID would work then there is less a chance on a million to meet a bug

    That's all......

    EDIT : sorry for the tonality of my message. I was just awake and im a bad guy the morning :)

  • Every other ID would work then there is less a chance on a million to meet a bug.

    Indeed starting w/ minimum values like 1, 2, 3 got high chances of duplicate pairs.
    Perhaps 11 is already a pretty enough starting value rather than 1000, but whatever! X_X
    I wish I had something better than multiplication for determining a pair uniqueness! :-<

Sign In or Register to comment.