Bubble popping animation

here…


// for explosions (these are actually Shrapnels)
ArrayList <Explosion> missiles; 

//
// ---------------------------------------------------------------
//
void setup() {
  // runs only once - init
  size(800, 600); 

  // explosions --------------------------------------
  // Create an empty ArrayList
  missiles = new ArrayList<Explosion>();   
  //
} // func

void draw() {
  // runs again and again

  // delete screen
  background(0, 64, 0);

  // explosions (show moving shrapnels)
  explosionManager();
} // func

//------------------------------------------------------------------------

void mousePressed() {
  explode(); // Init new explosion!!!!
}

void explode() {
  // Init new explosion!!!!
  // explode!
  missiles.clear();
  int maxMissiles = int(random(4, 222));
  for (int i=0; i<maxMissiles; i++) {    
    // this is where explode missile/shrapnel object is created 
    // and added to the missiles arrayList.
    // It is small (4) and life decrease is .72 (how fast it dies), 
    // no Line (false).
    missiles.add( 
      new Explosion(    
      random(mouseX-3, mouseX+3), random(mouseY-9, mouseY+9),   // POS: 
      random(-1.3, 1.3), random(-2.7, .6), 
      4, .72, false)); //
  }
} // method

//--------------------------------------------------------------------------------------------------
// the tab for Explosions and related and the complete class

void explosionManager() {
  // this is a new for loop. 
  // Actually for the Shrapnels.
  for (Explosion m : missiles) {
    m.decreaseLife(); // call the decrease life (for explosion)
    m.fly();          // call the "fly" method of the missile
    m.display();      // call the "display" method of the missile
  }
  //
  // remove dead ones (you need to have a conventional for-loop here) 
  for (int i=missiles.size()-1; i>=0; i--) {
    Explosion m = (Explosion) missiles.get(i);
    if (m.dead) {
      missiles.remove(i);
    }
  }
} // func

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

class Explosion {
  // ONE shrapnel 
  float startlocX, startlocY; // start pos 
  float x, y;          // current pos 
  float xvel, yvel;    // velocity
  float sizeMissile ;  // size for rect
  float life=20;       // how much lifes does it have
  float lifeDecrease;  // remove lifes
  boolean dead=false;  // is it alive? 
  boolean withLine;    // draw line? Explosion has none.
  //
  // contructor
  Explosion(
    float _startlocX, float _startlocY, 
    float _xvel, float _yvel, 
    float _size, float _lifeDecrease, 
    boolean _withLine) 
  {
    startlocX = _startlocX;
    startlocY = _startlocY;    
    x = startlocX;
    y = _startlocY;
    sizeMissile = _size;
    lifeDecrease=_lifeDecrease;
    xvel = _xvel;
    yvel = _yvel;
    withLine=_withLine;
  }  // contructor
  //
  void display() {
    //stroke(255, 2, 2);
    fill(255, 2, 2);
    noStroke();
    if (withLine) {
      line(startlocX, startlocY, x, y);
    }
    sizeMissile-=.07;
    rect(x, y, sizeMissile, sizeMissile);
  } // method
  //
  void fly() {
    x += xvel;
    y += yvel;
  } // method
  //
  void decreaseLife() {
    life-=lifeDecrease;
    if (life<=0 || sizeMissile<=0) {
      dead=true;
    }
  } // method
  //
} // class
//
// ======================================================================
3 Likes

as you see, the new explosion is started in explode()

the position for the explosion is mouse position

grab the color from the bubble that explodes

1 Like

new version with

  • color and also with
  • a bit of falling for the shrapnel’s.
  • ball rising and then shrinking and sinking
// for explosions (these are actually Shrapnels)
ArrayList <Shrapnel> shrapnels; 

// Test bubble
Ball ball1;

//
// ---------------------------------------------------------------
//
void setup() {
  // runs only once - init
  size(800, 600); 

  // explosions 
  // Create an empty ArrayList
  shrapnels = new ArrayList<Shrapnel>();
  ball1 = new Ball(); 
  //
} // func

void draw() {
  // runs again and again

  // delete screen
  background(0, 64, 0);

  // explosions (show moving shrapnels)
  explosionManager();

  // ball display 
  ball1.display();
} // func

//------------------------------------------------------------------------

void mousePressed() {
  // 
  ball1.stateBall=1;
}//func 

//--------------------------------------------------------------------------------------------------
// the tab for Explosions and related and the complete class

void explosionManager() {
  // this is a new for loop. 
  // Actually for the Shrapnels.
  for (Shrapnel m : shrapnels) {
    m.decreaseLife(); // call the decrease life (for explosion)
    m.fly();          // call the "fly" method of the missile
    m.display();      // call the "display" method of the missile
  }
  //
  // remove dead ones (you need to have a conventional for-loop here) 
  for (int i=shrapnels.size()-1; i>=0; i--) {
    Shrapnel m = (Shrapnel) shrapnels.get(i);
    if (m.dead) {
      shrapnels.remove(i);
    }
  }
} // func

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

class Ball {

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

  float x=random(55, width-55);
  float y=random( height-55, height);

  float yvel=-3; 

  int sizeellipse = 55;

  int stateBall = 0;

  boolean dead = false; 

  // NO constr 

  void display() {

    y+=yvel; 

    switch (stateBall) {
    case 0:
      // wait
      if (!dead) {
        fill(colorBall);
        ellipse(x, y, sizeellipse, sizeellipse);
      }
      break; 

    case 1: 
      // hit - shrink and sink 
      yvel=2; 
      sizeellipse--; 
      if (sizeellipse<=30)
        stateBall=2; 
      fill(colorBall);
      ellipse(x, y, sizeellipse, sizeellipse);
      break; 

    case 2:
      explode(x, y, colorBall); // Init new explosion!!!!
      // reset 
      dead=true; 
      stateBall=0; 
      ball1=new Ball(); 
      break;
    }//switch
  }

  void explode(  float x1, float y1, 
    color colorShrapnel) {
    // Init new explosion!!!!
    // explode!

    // clear old (optional)
    // shrapnels.clear();

    int maxshrapnels = int(random(14, 222));
    //color colorShrapnel = color(random(255), random(255), random(255)); 
    for (int i=0; i<maxshrapnels; i++) {    
      // this is where explode missile/shrapnel object is created 
      // and added to the shrapnels arrayList.
      // It is small (4) and life decrease is .72 (how fast it dies), 
      // no Line (false).
      shrapnels.add( 
        new Shrapnel(    
        random(x1-3, x1+3), random(y1-9, y1+9), // POS: 
        random(-1.3, 1.3), random(-2.7, .6), 
        4, .72, false, 
        colorShrapnel)
        ); //
    }
  } // method
  //
}//class

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

class Shrapnel {
  // ONE shrapnel 
  float startlocX, startlocY; // start pos 
  float x, y;          // current pos 
  float xvel, yvel;    // velocity
  float sizeMissile;   // size for rect
  float life=32;       // how much lifes does it have - e.g. 20 - this is the life span of the shrapnel
  float lifeDecrease;  // remove lifes
  boolean dead=false;  // is it alive? 
  boolean withLine;    // draw line? Explosion has none.

  color colorShrapnel = 0; // color(random(255), random(255), random(255)); 

  float gravity = 0.103;

  // contructor
  Shrapnel( float _startlocX, float _startlocY, 
    float _xvel, float _yvel, 
    float _size, float _lifeDecrease, 
    boolean _withLine, 
    color colorShrapnel_) {
    startlocX = _startlocX;
    startlocY = _startlocY;    
    x = startlocX;
    y = _startlocY;
    sizeMissile = _size;
    lifeDecrease=_lifeDecrease;
    xvel = _xvel;
    yvel = _yvel;
    withLine=_withLine;
    colorShrapnel=colorShrapnel_;
  }  // contructor

  void display() {
    fill(colorShrapnel);
    noStroke();
    if (withLine) {
      line(startlocX, startlocY, x, y);
    }
    sizeMissile-=.07;  // the size shrinks 
    rect(x, y, sizeMissile, sizeMissile);
  } // method

  void fly() {
    x += xvel;
    y += yvel;

    yvel += gravity;
  } // method

  void decreaseLife() {
    life-=lifeDecrease;
    if (life<=0 || sizeMissile<=0) {
      dead=true;
    }
  } // method
  //
} // class
//
// ===================================================
3 Likes

Wow!!
Amazing!

I can really use this example to learn a lot from!..
Thx!
My son will also be really impressed to and inspired!

3 Likes

Nice to hear this and thanks for your words!

Chrisir

1 Like

Hi! :slight_smile:
We are trying to use the stuff from your explosion code woth our bubble…
What we want is the bubble to be a object that is complete with all its functions:

  • Rising up
  • Wobbling
  • Popping when clicked on
    We have made a wobbling bubble that rises and the option to repeat/reset it.
    For that we now use 3 lines of code beside the line that we use to tell size (b1=newBubble(50);):
    Create it, make it move and reset at top.

We would want the bubble object to be like when creating a rect for example. You just say rect(value).
So… All of the coding would have to be done for the bubble class.
The main tab would only have so little code.
I guess that might not be possible… But is it possible to make it at least short as below and still all of the functionality built in?
Example:

Bubble b1;

void setup() {
  size(640, 360);
  b1 = new Bubble(50);
}
void draw() {
  background(0);
  noFill();
  stroke(255);
  b1.show();
}

Well… we havent been able to make your code and our bubble work so far as I said and I think we need assistans :slight_smile:

I’ll share our bubble code below.
Its 2 tabs (separated below with a bunch of ===)

Bubble b1;



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



void draw() {
  background(0);
  noFill();
  stroke(255);
  b1.show();
  b1.move();
  b1.top();

  println("Y", mouseY);
  println("RS", riseStart);
  println("X", mouseX);
  println("Strt", start);
}

void mousePressed() {
  if ((mouseX < start + w/2) && (mouseX > start - w/2) &&
    (mouseY < riseStart + h/2) && (mouseY > riseStart - h/2)) {
    fill(0, 255, 0);
    ellipse(100, 100, 20, 20);
    //setup();
  }
}
====================================================
//Bubble class tab


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 mX;
float mY;


class Bubble {


  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;
    mX = mouseX;
    mY = mouseY;
  }


  void show() {


    strokeWeight(2);
    ellipse (start, riseStart, w, h);
    if (move) {
      w = w + wspeed;
      //println(start, riseStart);



      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) { 
riseStart = tempSize + height+100;
start = random(0, 640);
  
  
  
}
}
}

Is your idea that, instead of calling b1.move(), b1.show(), b1.top(), you just want to call e.g. b1.all() – which then calls move, show, and top?

1 Like

Yeah, something like that…
I want our bubble to be as complete as possible :slight_smile:

Me and my son had a great session today practicing.
We made the bubble get replaced with a point that drops with gravity when clicked on.

Tried to make this new point a new object in a new tab and then run this in the bubble class tab.
Didn’t manage to figure it out today…
I need a variable from the bubble class to work in the new dropping point class.
The point needs to know where the bubble is when click so it can take it from there…
The variable that I use to track the bubble doesn’t work over in my new tab.

How do I do that? Use a object in a object?.. Also for making the code in the main tab short. :slight_smile:

2 Likes

You could also use one class.

Just have a flag or a state variable in that class that indicates whether to show a balloon or a point

1 Like

I should really have a look at states.
It was used in the explosion example I’ve got to use to try to make particles appear from the popped bubble.
We tried a little bit but I guess if this is the way to do it we should really read more about states.
Thx :blush:

In a full program state refers to different screens (start screen / Game / Help Screen / High score screen) or major situations of the sketch.

Here, state is the situation/ state of one bubble (raises or popped…)

It’s nothing complicated.

It just stores whether you clicked a bubble and then whether it’s exploded or sinking or dead. You store this information in int state and when it changes (in an explosion all shrapnels vanished) you change state accordingly (bubble is dead).

You also act on state (act accordingly to state), so when state is bubble, show bubble, when state is explode, show explosion.

It’s just a simple way to make animation with different steps/phases/situations/states.

1 Like

This is a test we did yesterday without any switch states…
its to sets out gravity and also a way to “switch state” with if.
When I click the mouse I change the size of the “ball” to zero with a variable and create a new “ball” with the size of 1 in the same spot. Also I stop the movement with “gravity” and the small new “ball” falls to the ground.

I tried adding “switch” to this code right now with no success :frowning:
Could you modify my code to work with switch?

Also… In this code… We tried really hard to re-spawn a new “ball” when the dead dropping ball exits the screen… Couldn’t make that happen either.

//Gravity test by Teljemo and son...
//Click anywhere to pop the ball and see the reaminting matter fall to the ground.
//To do: 
//Respawn ball when matter exits window.
//Change to states.


float gravity;      //Gravity variable
float x;            //Startpoint for ball in X
float upspeed;      //The speed of the ball rising.
float riseStart;    //Start point of the ball and position of ball (follows the ball)
boolean click = false;      //For mousepress (tried this way instead of a void mousePressed)
float bsize1;      //original size of ball
float bsize2;      //Size of dropping small ball

void setup() {
  size(640, 360);
  x = width/2;    //Ball rise from middle of window
  riseStart = height+bsize2;      //Ball starts from its own size below window
  bsize1 = 20;
  bsize2 = 1;
  upspeed = 5;
  gravity = 0.5;
}

void draw() {


  background(0);
  noFill();
  stroke(255);
  ellipse(x, riseStart, bsize1, bsize1);  //Ball with size1 as 20


  println("rS", riseStart);

  riseStart = riseStart - upspeed;
  if (mousePressed) {
    click = true;
  }

  if (click) {
    upspeed = upspeed - gravity;
    ellipse(x, riseStart, bsize2, bsize2); // new small ball created
    bsize1 = 0;    //The original ball size changet to 0 = invisible. Still follows "riseStart"
  }

//Tried to reset riseStart when the small ball exits the window to spawn a new ball.
  if (riseStart > height+bsize2) {
    riseStart = height+bsize2;
  }
}//draw
1 Like

Where do you want to add switch – and what do you want it to do?

switch case a case b case c is equivalent to if a if b if c. If you add break statements it is equivalent to if a else if b else if c.

1 Like

I want it to do the same thing as now.
The ball is rising. When clicking the ball change state to a really small ball that changes direction with gravity and falls down.
When it exits the window a new ball should rise up.
When this works I will move on to adding the pop “explosion” that should happen at the same time as the original ball disappears.

Finally we will try to add all this in to our bubble class code. :blush:

1 Like

first a word to switch() and case.

This simple program is without it.




int stateBubble=0; 

void setup() {
  size(700, 700);
}

void draw() {
  background(0); 
  text(stateBubble, 111, 111);
}

// ----------------------------------------------------

void keyPressed() {
  if (key=='0')
    stateBubble = 0; 
  else if (key=='1') 
    stateBubble = 1;
  else if (key=='2') 
    stateBubble = 2;
  else {
    //ignore
  }
}
//

Here is the same Sketch with switch().

As you can see, switch() has nothing to do with state but is there to evaluate one variable when it can have different values:

Here is is used to evaluate key :



int stateBubble=0; 

void setup() {
  size(700, 700);
}

void draw() {
  background(0); 
  text(stateBubble, 111, 111);
}

// ----------------------------------------------------

void keyPressed() {
  switch(key) {

  case '0':
    stateBubble = 0;
    break; 

  case '1':
    stateBubble = 1;
    break; 

  case '2': 
    stateBubble = 2;
    break; 

  default:
    //ignore
    break; 
    //
  }//switch
  //
}//function 
//
1 Like

Now I look at your last sketch

here is your mistake:

The upper screen border is not height but 0 (zero)

The lower part is height.

(The point 0,0 is upper left corner)

Hence you want

  //Tried to reset riseStart when the small ball exits the window to spawn a new ball.
  if (riseStart < 0) {

or

  //Tried to reset riseStart when the small ball exits the window to spawn a new ball.
  if (riseStart < bsize2) {
1 Like

Now I look at your draw and it’s a little confusing because a lot of ifs:

  if (mousePressed) {
    click = true;
  }

  if (click) {
    upspeed = upspeed - gravity;
    ellipse(x, riseStart, bsize2, bsize2); // new small ball created
    bsize1 = 0;    //The original ball size changet to 0 = invisible. Still follows "riseStart"
  }

//Tried to reset riseStart when the small ball exits the window to spawn a new ball.
  if (riseStart > height+bsize2) {

We can use state and switch() to make it better readable.

//Gravity test by Teljemo and son - NOW with states 
//Click anywhere to pop the ball and see the reaminting matter fall to the ground.
//To do: 
//Respawn ball when matter exits window.
//Change to states. Done. 

// 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 gravity;      //Gravity variable
float x;            //Startpoint for ball in X
float upspeed;      //The speed of the ball rising.
float riseStart;    //Start point of the ball and position of ball (follows the ball)

float bsize1;      //original size of ball
float bsize2;      //Size of dropping small ball

// ----------------------------------------------------------------------------------------

void setup() {
  size(640, 360);

  x = width/2;    //Ball rise from middle of window
  riseStart = height+bsize2;      //Ball starts from its own size below window
  bsize1 = 20;
  bsize2 = 3;
  upspeed = 5;
  gravity = 0.5;
} //function

void draw() {
  background(0);

  switch(state) {

  case RISE: 
    noFill();
    stroke(255);
    ellipse(x, riseStart, 
      bsize1, bsize1);  //Ball with size1 as 20
    riseStart = riseStart - upspeed;
    println("rS", riseStart);
    if (riseStart < bsize2) { // upper screen border 
      state = RESTART;
    }
    break; 

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

  case RESTART: 
    // restart 
    riseStart = height+bsize2+random(33, 333);
    state = RISE; 
    break;

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

// ----------------------------------------------------------------------------------------

void mousePressed() {
  state = FALL;
}//function 
//

Now I look at your sketch from Nov 30th

First, you had your variables outside the class.

They must be inside the class (it’s not enough to have it in the same tab. It’s still seen as global variables which is bad. It’s bad when you want to use multiple different bubbles)


  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 mX;
  float mY;

Now, in the previous sketch without the class I used state.
Putting it together
Sketch with state inside the class


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;

  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, 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;
  }

  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
//

Remember you can use ctrl-t for auto-format your sketch in processing.

Chrisir

2 Likes

Thanks a million!!..
This really helped us understand the switch function better :slight_smile:
With the bubble code now working with the “pop” and a small piece falling to the ground and also the reset function working as we want, we started looking at the “explosion” today.

We have now moved on in the “coding train course” on YT to arrays. (We have been waiting to start with that chapter until these other things were solved.)
Of course we got stuck after a couple of hours and I don’t want my teenager son to loose hope I need help on this to.

Our goal on this is to make particles/points appear on the click (case FALL:), (This will look like the ghost of the bubble when it bursts) then quickly dissiperar with a fade.
We have found a way on how to do the fade and we have a point working in a test program.
This point is set to appear at the radius border (hard-coded) of the bubble (a static circle in the test program) and then fade away.

We have made the array and can create many points but we got stuck in how to position them around the bubble.
Now, we need to have them appear all around the circle.

The problems:
Position of point cloud cant follow the dropping part.
Creation of points around where the bubble was when it was clicked. In the real bubble program, we use a variable name “riseStart” as the start point for the bubble and then retract (-) from this to make the bubble rise. The same variable is then reused by the dropping part with a bit of gravity added.
The point cloud we now want should not follow “riseStart” when it appears. The small part drops with this variable but the point cloud should stay!..
Positions of points around the bubble
We got stuck on this and decided to call it a day when we realized this might be including to many new things. On search we found trigonometry and my son haven’t even started on that in school. So, I felt that I need to check with you what the best way to do this is. Maybe there is a simple way that we haven’t found or figured out.

The test program:
In the test program below we use a static circle as bubble but use variables for position of it so we can pretend it could move (as the real bubble)
There is a array of 10 point lining up right now. We cant figure out how to get them to spawn where the circle was and then stop using “riseStart” to stay while fading out. Maybe move a little bit like a implode… hmm…
The code is one tab only.


float col = 255;
boolean boolFade;
boolean bFadeIn;

Matter[] matters = new Matter[10];

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

  for (int i = 0; i < matters.length; i++) {
    matters[i] = new Matter(50);
  }
}

//
//====================================================
// 
void draw() {
  background(0);

  for (int i =0; i < matters.length; i++) {
    matters[i].lol();
    matters[i].mFade();
  }
}
//
//====================================================
//
void mousePressed() {
  col = 0;
  boolFade = true;
  bFadeIn = !bFadeIn;
}
//
//====================================================
//

class Matter {

  float fade;
  int passedTime;
  int maxTime = 50;
  float rad;
  float riseStart;
  float x;
  float x_;
  float w;
  float h;
  float maxW;

  Matter(float tempSize) {

    rad = tempSize/2;
    riseStart = 100;
    x = 100;
    x_ = random(75,150);
    w = tempSize;
    h = tempSize;
    maxW = w*1.1;
  }
//
//====================================================
//
  void lol() {

    noFill();
    stroke(col);
    strokeWeight(1);
    ellipse(x, riseStart, w, h); // bubbla
    mFade();
  }
//
//====================================================
//
// the void below is from google. It was a rectangle fading in and out on click.
// We just commented out the "else" line in the code, we always want it to fade out. 
//Maybe more things can be cleaned up from this code. We were just glad it worked right now :)
  void mFade() {
    if (boolFade) {
      passedTime++;
      if (bFadeIn) {
        fade = map(maxTime - passedTime, 0, maxTime, 0, 255);
      } else {
        //fade = map(passedTime, 0, maxTime, 0, 255);
      }
      println(bFadeIn + " " + passedTime + " " + fade);
      if (fade > 254 || fade < 1) {
        boolFade = false;
        passedTime = 0;
      }
    }
    noFill();
    stroke(255, fade);
    strokeWeight(1);
    point(x_, riseStart-rad); // the point
  }
}//class

2 Likes

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 RADIUS = 80.8;

  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[0];

  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
    PointCircle newBullet = new PointCircle( cos(angle)*RADIUS+CENTER_X, sin(angle)*RADIUS+CENTER_Y);
    // 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).
It’s also with fading.


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

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

  final float RADIUS = 1.8;

  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[0];

  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)*RADIUS+CENTER_X, sin(angle)*RADIUS+CENTER_Y, 
      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;

  int fade = 255; 

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

  void display() {
    fill(255, 0, 0, fade); 
    noStroke();
    ellipse(posX, posY, 
      3, 3);
  }

  void move() {
    posX+=dirX;
    posY+=dirY;
    fade--;
  }
  //
}//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 RADIUS = 1.8;

    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[0];

    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)*RADIUS+start, sin(angle)*RADIUS+riseStart, 
        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;

  int fade = 255; 

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

  void display() {
    fill(255, 0, 0, fade); 
    noStroke();
    ellipse(posX, posY, 
      3, 3);
  }

  void move() {
    posX+=dirX;
    posY+=dirY;
    fade-=1;
  }
  //
}//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!. :joy:
Really cool! :slight_smile:

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 :slight_smile:

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 :slight_smile:

Then we cant figure out this:

class Fallout { 
  // Bullet

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

  int fade = 255; 

  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;
  float rad;

  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;

    rad=tempSize/2;
    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 RADIUS = rad;
    println(rad);
    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[0];

    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)*RADIUS+start, sin(angle)*RADIUS+riseStart, 
        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;

  int fade = 255; 

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

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

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