I am trying to fully understand the Java BouncyBubbles example.
Here’s the code:
int numBalls = 12;
float spring = 0.05;
float gravity = 0.03;
float friction = -0.9;
Ball[] balls = new Ball[numBalls];
void setup() {
size(640, 360);
for (int i = 0; i < numBalls; i++) {
balls[i] = new Ball(random(width), random(height), random(30, 70), i, balls);
}
noStroke();
fill(255, 204);
}
void draw() {
background(0);
for (Ball ball : balls) {
ball.collide();
ball.move();
ball.display();
}
}
class Ball {
float x, y;
float diameter;
float vx = 0;
float vy = 0;
int id;
Ball[] others;
Ball(float xin, float yin, float din, int idin, Ball[] oin) {
x = xin;
y = yin;
diameter = din;
id = idin;
others = oin;
}
void collide() {
for (int i = id + 1; i < numBalls; i++) {
float dx = others[i].x - x;
float dy = others[i].y - y;
float distance = sqrt(dx*dx + dy*dy);
float minDist = others[i].diameter/2 + diameter/2;
if (distance < minDist) {
float angle = atan2(dy, dx);
float targetX = x + cos(angle) * minDist;
float targetY = y + sin(angle) * minDist;
float ax = (targetX - others[i].x) * spring;
float ay = (targetY - others[i].y) * spring;
vx -= ax;
vy -= ay;
others[i].vx += ax;
others[i].vy += ay;
}
}
}
void move() {
vy += gravity;
x += vx;
y += vy;
if (x + diameter/2 > width) {
x = width - diameter/2;
vx *= friction;
}
else if (x - diameter/2 < 0) {
x = diameter/2;
vx *= friction;
}
if (y + diameter/2 > height) {
y = height - diameter/2;
vy *= friction;
}
else if (y - diameter/2 < 0) {
y = diameter/2;
vy *= friction;
}
}
void display() {
ellipse(x, y, diameter, diameter);
}
}
I don’t understand why in setup the creation of balls seem to refer to itself with the last parameter: balls[i] = new Ball(random(width), random(height), random(30, 70), i, **balls**);
Also, the link between others,oin and Ball is not clear as well:
Ball[] others;
Ball(float xin, float yin, float din, int idin, Ball[] oin) {
x = xin;
y = yin;
diameter = din;
id = idin;
others = oin;
}
Then, this for routine is strange: for (Ball ball : balls). Why neither semicolons nor comparison but a colon?
// balls is a list of objects of class Ball
// for (Ball ball : balls)
// means loop through all objects in list balls and give me each as :
// ball of class Ball
// more easy example:
String[] words = new String[] {"abc","def","ghi"};
for ( String word : words ) println(word);
/*
abc
def
ghi
*/
i also just read it and, what can i say:
you and me need another year of hard work before we would be able
to come up with that kind of idea / structured coding,
so let us forget how that is be done by the “genius” and start at the beginning:
WHY?
a class is a powerful thing what has grown over the decades
-a- you have basics like int float…
-b- you have array of that basics or even , but these are all same type
-c- to come over that limitation there has been
something like struct / records, a definition of a mix of variables of different type
( much like a data line in a excel table / the header line explains what they mean )
what now is the first step of a class
-d- more, add to the public “record” you can have local variables
-e- and that makes the today class: IT can have methods
but over all a class describes ONE object ( with public and private properties ++)
that is the
class Ball
and one object would be a “ball of type Ball”
Ball ball
or you can make a list / array of items of that type Ball
Ball balls
and that would be all independent from each other,
and the class Ball don’t even know that there are others
unless you make ( from the outside ) a loop over all “balls”
to check on something, like the distance of each / to each other.
But if you now not want do that check loop from the outside,
you might try to do that inside, as a method of the class,
what is impossible unless the class has a link to the others.
( and by the way, that is insofar a easy example as it refs to “its” array of this class,
it might be that you want to check on objects of a other class “bricks of Brick” )
and that link to the array is what you see in the Ball definition
Ball oin
used in the
Ball.collide()
method.
so, sorry, i am good with it, just to know something like this can be done.
i go back to make my own easy/beginner examples
Things became a bit less complex when I understood that ball was just the name of an iterator such as i in usual for loops and it has nothing to do with balls apart from the purpose of the sketch.
The loop could has been coded like this:
for (Ball dadido : balls) {
dadido.collide();
dadido.move();
dadido.display();
}
This is now clear but still it’s strange to have this part of code below, because it seems one needs to provide a Ball object to define a Ball object. So it seems there’s a self-reference.
Ball(float xin, float yin, float din, int idin, Ball[] oin) {
x = xin;
y = yin;
diameter = din;
id = idin;
others = oin;
}
no, not NEED, just WANT to use the data of a “external” array
funny that it is a array of its own class type
again, a class Ball does not know if/that you made a object ball or a array balls
of its or any kind.
Yes, it’s a way to avoid checking twice if a collision occurs between the two same balls. When you check the collision between the first ball and the others, there is a maximum number (2) of collisions to check, but the more you progress into the array of balls the number of collisions to check is reduced because actually these collisions have already been checked but from the opposite point of view, the other ball possibly involved.
The idea is that every `Ball` object you are creating get the list of all the other `Ball` objects that you have created before: that is the oin variable so it is not a self-reference.
In the code, every time you create a Ball object, you add it the the balls array and you also give that list to the constructor of the Ball object.
The first time, the balls array is empty and you create the first Ball object: let’s call it Ball01. Ball01 is now created and its others array is empty (since the balls one was).
Now let’s create the second one. The balls array contain 1 Ball object: Ball01. Ball02 is now created and its others array contain Ball01.
And so on and so on. This way the others array of Ball03 will have Ball01 and Ball02 inside.
The idea is that after, when you want to collide you can just loop through all your Ball in the balls array without having to check for double collisions. You ca simply call the collide method that will check collision only with the Ball in others so only with the Ball created before.
That was my basic understanding. However if the instance’s (?) name is different, the class/objet is the same and seems to refer to itself. The class includes an array with objects ot its own kind and which have not been defined yet?
class Ball {
...
Ball[] others;
And how can the description of the object Ball include an array of Ball??? Ball(float xin, float yin, float din, int idin, Ball[] oin)