 # Bubble popping animation

Hello!

Here is a simple sketch showing the use of cos and sin (taken from this forum).

This way you get a circle around a point.

``````PointCircle[] points; //might want to use a list (ArrayList)

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

final float ANGLE_INCREMENT = TWO_PI/10;
//2PI would only shoot down, PI is up down,
//halfPi is in 4 dirs and so on
//you can also just use some random number like 0.3256
//but try keeping it within 0-2PI

points = new PointCircle;

for (int i=0; i<10; i++) {
float angle=i*ANGLE_INCREMENT;
float CENTER_X=width/2;
float CENTER_Y=height/2;
// make a new bullet
// append it to array
points = (PointCircle[]) append(points, newBullet);
}
}

void draw() {
background(255);

for (int i = 0; i < points.length; i++) {
points[i].display();
}//for
}////func

// ================================================================================

class PointCircle {
// Bullet

float posX, posY;

PointCircle (float x, float y ) {
posX = x;
posY = y;
}

void display() {
fill(255, 0, 0);
ellipse(posX, posY,
3, 3);
}
//
}//class
//
``````

Here is another explosion based on the cos sin sketch (also from this forum).

``````
Bullet[] bullets; //might want to use a list (ArrayList)

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

final float ANGLE_INCREMENT = TWO_PI/10;
//2PI would only shoot down, PI is up down,
//halfPi is in 4 dirs and so on
//you can also just use some random number like 0.3256
//but try keeping it within 0-2PI

bullets = new Bullet;

for (int i=0; i<10; i++) {
float angle=i*ANGLE_INCREMENT;
float CENTER_X=width/2;
float CENTER_Y=height/2;
// make a new bullet
Bullet newBullet = new Bullet(
cos(angle)*0.8, sin(angle)*0.8);
// append it to array
bullets = (Bullet[]) append(bullets, newBullet);
}
}

void draw() {
background(255);

for (int i = 0; i < bullets.length; i++) {
bullets[i].display();
bullets[i].move();
}//for
}////func

// =======================================================================

class Bullet {
// Bullet

float posX, posY;
float dirX;
float dirY;

Bullet (float x, float y,
float dx, float dy) {
posX = x;
posY = y;
dirX = dx;
dirY = dy;
}

void display() {
noStroke();
ellipse(posX, posY,
3, 3);
}

void move() {
posX+=dirX;
posY+=dirY;
}
//
}//class
//
``````

Please note, that it has a class Bullet which represents one circle (shrapnel) of the explosion.

On sketch level (outside the class) is an array of that class.

For your sketch that means that when a ball explodes (and there could be multiple balls with multiple explosions) you start a explosion like in this sketch.

So best when each ball has an array bullets inside it.

You then need the class Bullet.

``````
Bubble b1;

void setup() {
size(640, 360);
b1 = new Bubble(50);
}

void draw() {
background(0);
b1.all();
}

void mousePressed() {
if (b1.over()) {
b1.fall();
}
}

//====================================================
//Bubble class tab

class Bubble {

// constants: these are values that state can have (must be unique (0,1,2...))
final int RISE    = 0;   // the word final makes them constants
final int FALL    = 1;
final int RESTART = 2;
// variable: current value of the state
int state=RISE;  // not a state of the program, but the state of the ball

float tempSize;
float w;
float h;
boolean move = true;
float maxW;
float maxH;
float minW;
float minH;
float wspeed;
float hspeed;
float riseY = random(0.5, 2);
float riseStart;
float start = random(0, 640);
float gravity = 0.5;

Bullet[] bullets; //might want to use a list (ArrayList)

Bubble(float tempSize) {
w = tempSize;
h = tempSize;
riseStart = tempSize + height;

maxW = w*1.1+random(0, maxW/2);
maxH = h*1.1+random(0, maxH/1);
minW = w/1.1;
minH = h/1.1;
wspeed = w/100;
hspeed = h/75;
}

void all() {
// all (or script())

print("Y ", mouseY);
print("  RS ", b1.riseStart);
print("  X ", mouseX);
println("  Start", b1.start);

switch(state) {

case RISE:
show();
move();
top();
break;

case FALL:
riseY = riseY - gravity;
riseStart = riseStart - riseY;
ellipse(start, riseStart,
3, 3); // new small ball
showExplosion();
if (riseStart>height+133) {  // lower screen border
state = RESTART;
riseY = 5;
}
break;

case RESTART:
// restart
state = RISE;
riseStart = tempSize + height+100;
start = random(w, width-w);
break;

default:
// Error
println("Error. Unknown state ");
exit();
break;
//
}//switch
//
} // method

void show() {
//noFill();
//stroke(255);
fill(255, 0, 0); // RED
noStroke();
strokeWeight(2);
ellipse (start, riseStart,
w, h);

if (move) {
w = w + wspeed;

if ((w > maxW) || (w < minW)) { // Makes bubble wobble.
wspeed = wspeed * -1;
}

if (move) {
h = h + hspeed;
}
if ((h > maxH) || (h < minH)) { // Makes bubble wobble.
hspeed = hspeed * -1;
}
}
}

void move() {
riseStart = riseStart - riseY;
}

void top() {
if (riseStart < tempSize - tempSize -100) {
state=RESTART;
}
}

void fall() {
state=FALL;
explode();
}

boolean over() {
// returns true or false; true when mouse is on balloon.
// You had this in mousePressed before.
return
(mouseX < start + w/2) &&
(mouseX > start - w/2) &&
(mouseY < riseStart + h/2) &&
(mouseY > riseStart - h/2);
}

void showExplosion() {
for (int i = 0; i < bullets.length; i++) {
bullets[i].display();
bullets[i].move();
}//for
}

void explode() {

final float ANGLE_INCREMENT = TWO_PI/10;
//2PI would only shoot down, PI is up down,
//halfPi is in 4 dirs and so on
//you can also just use some random number like 0.3256
//but try keeping it within 0-2PI

// full reset
bullets = new Bullet;

for (int i=0; i<10; i++) {
float angle=i*ANGLE_INCREMENT;
// make a new bullet at CURRENT POSITION : start, riseStart
Bullet newBullet = new Bullet(
cos(angle)*0.8, sin(angle)*0.8);
// append it to array
bullets = (Bullet[]) append(bullets, newBullet);
}
}
}//class

// ================================================================================

class Bullet {
// Bullet

float posX, posY;
float dirX;
float dirY;

Bullet (float x, float y,
float dx, float dy) {
posX = x;
posY = y;
dirX = dx;
dirY = dy;
}

void display() {
noStroke();
ellipse(posX, posY,
3, 3);
}

void move() {
posX+=dirX;
posY+=dirY;
}
//
}//class
//

``````

Chrisir

(I also showed you an explosion above some weeks ago)

2 Likes

Me and my son looked at this tonight.
We have been taking baby steps and much of this code is way beyond our level as we follow the “Learning Processing” book and tutorials by Daniel Shiffman. We sertanly notice progress by the fact we are actually seeing things in the code examples more now than before!. Really cool! There is some things we couldn’t figure out.
Our bubble is made with variables all along so everything connects. This is so we can set it to a different size and the wobble will adapt.
When we tries to do this with the “bullets” (now renamed fallouts in the code) we cant figure out how to change this.

We changed the “final float RADIOUS = 1,8” to a variable called “rad” that is based on the bubble dimeter/2. This worked to make the fallout start from the bubble edge Then we want to be able to change the number of fallouts depending on the size of the bubble but this we couldn’t find.
The number seems to be hardcoded here:
final float ANGLE_INCREMENT = TWO_PI/10;
and
for (int i=0; i<10; i++) {
I tried using fallout.lenght and “i” but it didn’t work in this case?

We also want to change how far and how fast the fallout moves. We want to have it move a bit less and maybe try some small random here. Could find where to do this?
Is it possible to create the dots a little more random around the circle? just some pixels? So it doesn’t look so perfect Then we cant figure out this:

``````class Fallout {
// Bullet

float posX, posY; **// pos and dir variables crated, no values..**
float dirX;
float dirY;

Fallout (float x, float y, **// x,y,dx and dy variables created, where do they get there values from?**
float dx, float dy) {
posX = x; **// variables with values taken from somewhere and used where? Now getting what value**
posY = y;
dirX = dx;
dirY = dy;
``````

Also some small question marks.

• Why is riseY reminding the program of its original values in FALL already and not in RESTART?
• The default state? when does this appear? And the exit() line. Does it close the viewer?

Played around with it some more and this is what I came up with…
Still cant figure out a lot of the above…

``````Bubble b1;

void setup() {
size(640, 360);
b1 = new Bubble(50);
}

void draw() {
background(0);
b1.all();
}

void mousePressed() {
if (b1.over()) {
b1.fall();
}
}

class Bubble {

// constants: these are values that state can have (must be unique (0,1,2...))
final int RISE    = 0;   // the word final makes them constants
final int FALL    = 1;
final int RESTART = 2;
// variable: current value of the state
int state=RISE;  // not a state of the program, but the state of the ball

float tempSize;
float w;
float h;
boolean move = true;
float maxW;
float maxH;
float minW;
float minH;
float wspeed;
float hspeed;
float riseY = random(0.8, 3);
float riseStart;
float start = random(0, 640);
float gravity = 0.3;

Fallout[] fallouts; //might want to use a list (ArrayList)

Bubble(float tempSize) { // <----------------- Bubble takes value from tab 1 and makes tempSize

w = tempSize;
h = tempSize;
riseStart = tempSize + height;

maxW = w*1.1+random(0, maxW/2);
maxH = h*1.1+random(0, maxH/1);
minW = w/1.1;
minH = h/1.1;
wspeed = w/100;
hspeed = h/75;

//println(tempSize);
}

void all() {
stroke(255,255);
// all (or script())

//print("Y ", mouseY);
//print("  RS ", b1.riseStart);
//print("  X ", mouseX);
//println("  Start", b1.start);

switch(state) {

case RISE:
show();
move();
top();
break;

case FALL:
riseY = riseY - gravity;
riseStart = riseStart - riseY;
ellipse(start, riseStart,
3, 3); // new small ball
showExplosion();
if (riseStart>height+133) {  // lower screen border
state = RESTART;
riseY = random(0.8, 3); // Why do we put this hera and not in case RESTART?
}
break;

case RESTART:
// restart
state = RISE;
riseStart = tempSize + height+100;
start = random(w, width-w);
break;

default: // What does this state do? When does it run?
// Error
println("Error. Unknown state ");
exit();
break;
//
}//switch
//
} // method

void show() {
//noFill();
//stroke(255);
noFill();
stroke(255,255);
strokeWeight(1);
ellipse (start, riseStart,
w, h);

if (move) {
w = w + wspeed;

if ((w > maxW) || (w < minW)) { // Makes bubble wobble.
wspeed = wspeed * -1;
}

if (move) {
h = h + hspeed;
}
if ((h > maxH) || (h < minH)) { // Makes bubble wobble.
hspeed = hspeed * -1;
}
}
}

void move() {
riseStart = riseStart - riseY;
}

void top() {
if (riseStart < tempSize - tempSize -100) {
state=RESTART;
}
}

void fall() {
state=FALL;
explode();
}

boolean over() {
// returns true or false; true when mouse is on balloon.
// You had this in mousePressed before.
return
(mouseX < start + w/2) &&
(mouseX > start - w/2) &&
(mouseY < riseStart + h/2) &&
(mouseY > riseStart - h/2);
}

void showExplosion() {
for (int i = 0; i < fallouts.length; i++) {
fallouts[i].display();
fallouts[i].move();
}//for
}

void explode() {

final float ANGLE_INCREMENT = TWO_PI/15;
//2PI would only shoot down, PI is up down,
//halfPi is in 4 dirs and so on
//you can also just use some random number like 0.3256
//but try keeping it within 0-2PI

// full reset
fallouts = new Fallout;

for (int i=0; i<15; i++) {
float angle=i*ANGLE_INCREMENT;
// make a new bullet at CURRENT POSITION : start, riseStart
Fallout newFallout = new Fallout(
cos(angle)*0.8, sin(angle)*0.8);
// append it to array
fallouts = (Fallout[]) append(fallouts, newFallout);
}
}
}//class

class Fallout {
// Bullet

float posX, posY;
float dirX;
float dirY;

Fallout (float x, float y,
float dx, float dy) {
posX = x;
posY = y;
dirX = dx;
dirY = dy;
}

void display() {
noStroke();
ellipse(posX, posY,
1, 1);
}

void move() {
posX+=random(-dirX/5,dirX);
posY+=random(dirY,-dirY/2);
}
//
}//class
``````

It’s in the class Bullet, method `display()` : the ellipse command.

In the method explode(), note that new Bullet (explosion shrapnel or splinters) is generated with 4 parameters: the first two are the position (around the bubble) the second two is the speed of the shrapnel (away from the bubble).

I think replace 10 (in both places) by 20 or whatever.

Where you initiate the 10 bullets - the 2nd two parameters (number 3 and 4) are the speed

default belongs to `switch()`. It’s doing the same as the else in if else…: it takes care of the cases we forgot. In our case this would apply if `state` had a value that we didn’t expect. This would be an error. The exit() would terminate the program. But it’s necessary to check whether state has a wrong value and to register this immediately and terminate the program.

Maybe you should read the tutorial on objects. In this part (named the constructor) in the class we initiate a new Bullet. It gets its values from the parameters of this specific function (the constructor) and these are from the parameters copied into the bullet properties. That’s how objects (the cookies) are made from the class (the cookie maker).
You call this part here:

``````      // make a new bullet at CURRENT POSITION : start, riseStart
Fallout newFallout = new Fallout(
cos(angle)*0.8, sin(angle)*0.8);
``````
2 Likes

Hi all. Here is some simple code slightly modified from some teaching material I use with my students. Hope it is useful!

``````void setup() {
size(960, 540, P2D);
background(0);
smooth(8);
createBubbles(100);
}

void draw() {
background(0);
doBubbles();
}

void mousePressed() {
checkIfBubbleHit(mouseX, mouseY);
}

//////////////////////////////
// BUBBLE CLASS AND HELPERS //
//////////////////////////////
// An arraylist to hold all the bubbles
ArrayList<Bubble> bubbles = new ArrayList<Bubble>();

// An easy way to make lots of them
void createBubbles(int _thisMany) {
for (int i = 0; i < _thisMany; i++) {
}
}
// An easy way to step through, update and display them all
void doBubbles() {
for (Bubble b : bubbles) {
b.update();
b.display();
}
}
// Check all bubbles to see if they have been clicked on
void checkIfBubbleHit(int _mx, int _my) {
for (Bubble b : bubbles) {
b.checkIfHit(_mx, _my);
}
}

//////////////////
// BUBBLE CLASS //
class Bubble {
float x, y, diam, diamBurst, floatSpeed;
float originalDiam;
int wobbleOffset = int(random(10000));
int state = 0; // 0 = normal; 1 = clicked;
Bubble() {
reset();
}
void reset() {
diam = random(40, 70);
originalDiam = diam; // we use this for our burst dots mapping
x = random(diam, width - diam);
y = height + (diam/2);
floatSpeed = random(0.5, 2);
diamBurst = diam + 50;
state = 0;
}
void update() {
switch(state) {
case 0: // normal rising bubble
y = y - floatSpeed;
if (y <= -diam/2) {
reset(); // off the top without being clicked? reset to bottom
}
break;
case 1: // bubble has been clicked on
diam = lerp(diam, diamBurst, 0.1); // burst!
break;
}
}
void display() {
switch(state) {
case 0: // normal rising bubble
fill(255, 32);
stroke(255);
strokeWeight(1);
// simple wobble using sin, cos and frameCount
// random wobbleOffset variable means they don't all wobble at the same time
float xDiam = diam + sin(radians(wobbleOffset + frameCount*5))*5;
float yDiam = diam + cos(radians(wobbleOffset + frameCount*5))*5;
ellipse(x, y, xDiam, yDiam);
break;
case 1: // bursting bubble
// draw the burst dots
int numBurstDots = 60;
strokeWeight(3);
float burstDotAlpha = map(diam, originalDiam, diamBurst, 255, 0); // makes our burst dots fade out
stroke(255, burstDotAlpha);
for (int i = 0; i < numBurstDots; i++) {
float bx = sin(angleStep*i)*diam/2;
float by = cos(angleStep*i)*diam/2;
point(x + bx, y + by);
}
if (diam >= diamBurst) { // burst yet?
reset(); // reset it!
}
break;
}
}
void checkIfHit(int _mx, int _my) {
// check distance from centre of bubble
if (dist(x, y, _mx, _my) < diam/2) {
state = 1;
}
}
}
``````
2 Likes

Thanks for that!

I worked further on Teljemos version

``````
Bubble b1;

void setup() {
size(640, 360);
b1 = new Bubble(50);
}

void draw() {
background(0);

// bubble management
b1.all();
}

void mousePressed() {
// bubble explodes
if (b1.over()) {
b1.fall();
}
}

// ========================================================================================================

class Bubble {

// constants: these are values that state can have (must be unique (0,1,2...))
final int RISE    = 0;   // the word final makes them constants
final int FALL    = 1;
final int RESTART = 2;
// variable: current value of the state
int state=RISE;  // not a state of the program, but the state of the bubble

float tempSize;
float w;
float h;
boolean move = true;
float maxW;
float maxH;
float minW;
float minH;
float wspeed;
float hspeed;
float riseY = random(0.8, 3);
float riseStart;
float start = random(0, 640);
float gravity = 0.3;

Fallout[] fallouts; //might want to use a list (ArrayList)

Bubble(float tempSize) { // <----------------- Bubble takes value from tab 1 and makes tempSize

w = tempSize;
h = tempSize;
riseStart = tempSize + height;

maxW = w*1.1+random(0, maxW/2);
maxH = h*1.1+random(0, maxH/1);
minW = w/1.1;
minH = h/1.1;
wspeed = w/100;
hspeed = h/75;
}

void all() {
// all (or script())

stroke(255, 255);

//print("Y ", mouseY);
//print("  RS ", b1.riseStart);
//print("  X ", mouseX);
//println("  Start", b1.start);

switch(state) {

case RISE:
// rise
show();
move();
top();
break;

case FALL:
//fall
riseY = riseY - gravity;
riseStart = riseStart - riseY;
// new small ball
ellipse(start, riseStart,
3, 3);
//shrapnels
showExplosion();
// lower screen border?
if (riseStart>height+133) {
state = RESTART;
}
break;

case RESTART:
// restart
state = RISE;
riseY = random(0.8, 3);
riseStart = tempSize + height+100;
start = random(w, width-w);
break;

default:
// What does this state do? When does it run?
// It just picks up an error, when we forgot a state.
// Error
println("Error. Unknown state ");
exit();
break;
//
}//switch
//
} // method

void show() {
//noFill();
//stroke(255);
noFill();
stroke(255, 255);
strokeWeight(1);
ellipse (start, riseStart,
w, h);

if (move) {
w = w + wspeed;

if ((w > maxW) || (w < minW)) { // Makes bubble wobble.
wspeed = wspeed * -1;
}

if (move) {
h = h + hspeed;
}
if ((h > maxH) || (h < minH)) { // Makes bubble wobble.
hspeed = hspeed * -1;
}
}
}

void move() {
riseStart = riseStart - riseY;
}

void top() {
if (riseStart < tempSize - tempSize -100) {
state=RESTART;
}
}

void fall() {
state=FALL;
explode();
}

boolean over() {
// returns true or false; true when mouse is on balloon.
return
(mouseX < start + w/2) &&
(mouseX > start - w/2) &&
(mouseY < riseStart + h/2) &&
(mouseY > riseStart - h/2);
}

void showExplosion() {
for (int i = 0; i < fallouts.length; i++) {
fallouts[i].display();
fallouts[i].move();
}//for
}

void explode() {

// init a new explosion

//2PI would only shoot down, PI is up down,
//halfPi is in 4 dirs and so on
//you can also just use some random number like 0.3256
//but try keeping it within 0-2PI

// full reset
fallouts = new Fallout;

// How many shrapnels? Random :
final int upperBound = int(random(8, 44));

// angle step accordingly
final float ANGLE_INCREMENT = TWO_PI/upperBound;

// angle
float angle=0;

for (int i=0; i<=upperBound; i++) {

// make a new bullet at CURRENT POSITION : start, riseStart
Fallout newFallout = new Fallout(
start, riseStart, // start pos
cos(angle)*random(.9, 3.8), sin(angle)*random(.9, 3.8) // speed of movement
);

// append it to array
fallouts = (Fallout[]) append(fallouts, newFallout);
angle=i*ANGLE_INCREMENT;
}//for
}//method
//
} //class

// ========================================================================================================

class Fallout {

// Bullet

float posX, posY;
float dirX, dirY;

float sizeFallout=random(0.3, 2.8);

color colorFallout = color(random(255), random(255), random(255)) ;

Fallout ( float x_, float y_,
float dx_, float dy_) {

posX = x_;
posY = y_;
dirX = dx_;
dirY = dy_;
}

void display() {
noStroke();
ellipse(posX, posY,
sizeFallout, sizeFallout);
}

void move() {
posX+=dirX;
posY+=dirY;
}
//
}//class
//
``````
1 Like

Awesome examples @GSA_IxD, Very interesting to see a code written in a different way with the same result!
Thx for that!

And since you left a bunch of comments I have been able to change it to what we are looking for I added the cos and sin plus the rad variable here to start the fallout from around the circle again
Also changed the speed and direction of the explosion. (since its mot of a popping bubble than exploding fireworks) ``````      // make a new bullet at CURRENT POSITION : start, riseStart
Fallout newFallout = new Fallout(
cos(angle)*random(-1.2, 0.8), sin(angle)*random(-1.2, 0.8) // speed of movement
``````

The upperBound variable should work fine to randomize the number of “particles”. maybe even better than number based on size of main bubble…

Super cool!.. Thx a lot.
Now we are gonna make a array of bubble objects. After that the son said he would like to try rewriting the code for sphere instead of ellipse… Here’s the code with our small edits… Working as we want it to! Thx!

``````Bubble b1;

void setup() {
size(640, 360);
b1 = new Bubble(150);
}

void draw() {
background(0);

// bubble management
b1.all();
}

void mousePressed() {
// bubble explodes
if (b1.over()) {
b1.fall();
}
}

// ========================================================================================================

class Bubble {

// constants: these are values that state can have (must be unique (0,1,2...))
final int RISE    = 0;   // the word final makes them constants
final int FALL    = 1;
final int RESTART = 2;
// variable: current value of the state
int state=RISE;  // not a state of the program, but the state of the bubble

float tempSize;
float w;
float h;
boolean move = true;
float maxW;
float maxH;
float minW;
float minH;
float wspeed;
float hspeed;
float riseY = random(1, 3);
float riseStart;
float start = random(0, 640);
float gravity = 0.3;

Fallout[] fallouts; //might want to use a list (ArrayList)

Bubble(float tempSize) { // <----------------- Bubble takes value from tab 1 and makes tempSize

w = tempSize;
h = tempSize;
riseStart = tempSize + height;

maxW = w*1.1+random(0, maxW/2);
maxH = h*1.1+random(0, maxH/1);
minW = w/1.1;
minH = h/1.1;
wspeed = w/100;
hspeed = h/75;
}

void all() {
// all (or script())

stroke(255, 100);
fill(255,200);

//print("Y ", mouseY);
//print("  RS ", b1.riseStart);
//print("  X ", mouseX);
//println("  Start", b1.start);

switch(state) {

case RISE:
// rise
show();
move();
top();
break;

case FALL:
//fall
riseY = riseY - gravity;
riseStart = riseStart - riseY;
// new small ball

ellipse(start, riseStart,
//shrapnels
showExplosion();
// lower screen border?
if (riseStart>height+133) {
state = RESTART;
}
break;

case RESTART:
// restart
state = RISE;
riseY = random(1, 3);
riseStart = tempSize + height+100;
start = random(w, width-w);
break;

default:
// What does this state do? When does it run?
// It just picks up an error, when we forgot a state.
// Error
println("Error. Unknown state ");
exit();
break;
//
}//switch
//
} // method

void show() {
//noFill();
//stroke(255);
fill(255,50);
stroke(255, 255);
strokeWeight(1);
ellipse (start, riseStart,
w, h);

if (move) {
w = w + wspeed;

if ((w > maxW) || (w < minW)) { // Makes bubble wobble.
wspeed = wspeed * -1;
}

if (move) {
h = h + hspeed;
}
if ((h > maxH) || (h < minH)) { // Makes bubble wobble.
hspeed = hspeed * -1;
}
}
}

void move() {
riseStart = riseStart - riseY;
}

void top() {
if (riseStart < tempSize - tempSize -100) {
state=RESTART;
}
}

void fall() {
state=FALL;
explode();
}

boolean over() {
// returns true or false; true when mouse is on balloon.
return
(mouseX < start + w/2) &&
(mouseX > start - w/2) &&
(mouseY < riseStart + h/2) &&
(mouseY > riseStart - h/2);
}

void showExplosion() {
for (int i = 0; i < fallouts.length; i++) {
fallouts[i].display();
fallouts[i].move();
}//for
}

void explode() {

// init a new explosion

//2PI would only shoot down, PI is up down,
//halfPi is in 4 dirs and so on
//you can also just use some random number like 0.3256
//but try keeping it within 0-2PI

// full reset
fallouts = new Fallout;

// How many shrapnels? Random :
final int upperBound = int(random(8, 44));

// angle step accordingly
final float ANGLE_INCREMENT = TWO_PI/upperBound;

// angle
float angle=0;

for (int i=0; i<=upperBound; i++) {

// make a new bullet at CURRENT POSITION : start, riseStart
Fallout newFallout = new Fallout(
cos(angle)*random(-1.2, 0.8), sin(angle)*random(-1.2, 0.8) // speed of movement
);

// append it to array
fallouts = (Fallout[]) append(fallouts, newFallout);
angle=i*ANGLE_INCREMENT;
}//for
}//method
//
} //class

// ========================================================================================================

class Fallout {

// Bullet

float posX, posY;
float dirX, dirY;

float sizeFallout=random(0.3, 2.8);

Fallout ( float x_, float y_,
float dx_, float dy_) {

posX = x_;
posY = y_;
dirX = dx_;
dirY = dy_;
}

void display() {
noStroke();
ellipse(posX, posY,
sizeFallout, sizeFallout);
}

void move() {
posX+=dirX;
posY+=dirY;
}
//
}//class
//
``````
2 Likes

Nice to hear this!

Chrisir

1 Like

I mentioned the tutorials:

2 Likes

What if the bubbles would explode on clashing with each other??

1 Like

great idea, love to see your code.

I tried it. But it’s not working. I think because of the condition I’ve written for a bubble to pop, each bubble is getting popped by itself. Haven’t been able to rectify it though.

``````Bubble [] bubbles = new Bubble  ;

void setup () {

size (640, 480);

for (int indices = 0; indices < bubbles.length; indices += 1) {

bubbles [indices] = new Bubble (random (width), height, random (80));
}
}

void draw () {

background (0);

for (int indices = 0; indices < bubbles.length; indices += 1) {

bubbles[indices].ascend ();
if (bubbles [indices].together (bubbles [indices])) {
bubbles[indices].pops ();
}
bubbles[indices].display ();
bubbles[indices].top ();
}
}

class Bubble {

float x, y;
float d;
float driftX;
float speedY;
float alpha;

Bubble (float tempX, float tempY, float tempD) {

x = tempX;
y = tempY;
d = tempD;
driftX = 2;
speedY = random (0.25, 2);
alpha = random (20, 107);
}

void display () {

fill (255, 223 + (random (-20, 0)), 0, alpha);
noStroke ();
ellipse (x, y, d, d);
}

void ascend () {

x += random (driftX*-1, driftX);

y -= speedY;
}

void top () {

if (y+d < 0) {

y = height;
}
}

boolean together (Bubble other) {

float distance = dist((x + d/2), (y+d/2), (other.x+((other.d)/2)), (other.y+((other.d)/2)));

if (distance == 0) {
return true;
} else {
return false;
}
}

void pops () {

d = 0;
}
}
``````

I think in draw you need nested for loop, to check each bubble against every other bubble:

``````  for (int indices = 0; indices < bubbles.length-1; indices += 1) {
for (int indices2 = indices ; indices2 < bubbles.length; indices2 += 1) {
if (bubbles [indices].together (bubbles [indices2])) {
bubbles[indices].pops ();
bubbles[indices2].pops ();
}
}
}
``````
``````Bubble b1;

void setup() {
size(640, 360);
b1 = new Bubble(50);
}

void draw() {
background(#B3E9F2); //sky blue
b1.all();
}

void mousePressed() {
if (b1.over()) {
b1.fall();
}
}

//====================================================
//Bubble class tab

class Bubble {

// constants: these are values that state can have (must be unique (0,1,2...))
final int RISE    = 0;   // the word final makes them constants
final int FALL    = 1;
final int RESTART = 2;
// variable: current value of the state
int state=RISE;  // not a state of the program, but the state of the ball

float tempSize;
float w;
float h;
boolean move = true;
float maxW;
float maxH;
float minW;
float minH;
float wspeed;
float hspeed;
float riseY = random(0.5, 2);
float riseStart;
float start = random(0, 640);
float gravity = 0.5;

Bubble(float tempSize) {
w = tempSize;
h = tempSize;
riseStart = tempSize + height;

maxW = w*1.1+random(0, maxW/2);
maxH = h*1.1+random(0, maxH/1);
minW = w/1.1;
minH = h/1.1;
wspeed = w/100;
hspeed = h/75;
}

void all() {
// all (or script())

print("Y ", mouseY);
print("  RS ", b1.riseStart);
print("  X ", mouseX);
println("  Start", b1.start);

switch(state) {

case RISE:
show();
move();
top();
break;

case FALL:
riseY = riseY - gravity;
riseStart = riseStart - riseY;
ellipse(start, riseStart,
3, 3); // new small ball
if (riseStart>height+133) {  // lower screen border
state = RESTART;
riseY = 5;
}
break;

case RESTART:
// restart
state = RISE;
riseStart = tempSize + height+100;
start = random(w, width-w);
break;

default:
// Error
println("Error. Unknown state ");
exit();
break;
//
}//switch
//
} // method

void show() {
//noFill();
//stroke(255);
fill(255, 255, 255,130); // RED //new-white transparent
strokeWeight(1);
ellipse (start, riseStart,
w, h);

if (move) {
w = w + wspeed;

if ((w > maxW) || (w < minW)) { // Makes bubble wobble.
wspeed = wspeed * -1;
}

if (move) {
h = h + hspeed;
}
if ((h > maxH) || (h < minH)) { // Makes bubble wobble.
hspeed = hspeed * -1;
}
}
}

void move() {
riseStart = riseStart - riseY;
}

void top() {
if (riseStart < tempSize - tempSize -100) {
state=RESTART;
}
}

void fall() {
state=FALL;
}

boolean over() {
// returns true or false; true when mouse is on balloon.
// You had this in mousePressed before.
return
(mouseX < start + w/2) &&
(mouseX > start - w/2) &&
(mouseY < riseStart + h/2) &&
(mouseY > riseStart - h/2);
}
//
}//class
//
``````

In my code, this code above must be

for (int indices2 = indices + 1

obviously

Sorry

But you don’t have a collision anyway

Welcome to the forum!

Great to have you here!