class MistGenerator {
  float xPos;
  float yPos;
  float zPos;
  
  ArrayList<mistParticle> particleList;
  
  public MistGenerator(float x, float y, float z) {
    xPos = x;
    yPos = y;
    zPos = z;
    particleList = new ArrayList<mistParticle>();
    makeMist();
  }
  
  void makeMist() {
    for(int i = 0; i < 25; i ++){
      particleList.add(new mistParticle(xPos + random(-400, 400) , yPos + random(-300, 200) , zPos));
    }
  }
  
  void spawnNewParticle() {
    particleList.add(new mistParticle(xPos + random(-400, 400) , yPos + random(-300, 200) , zPos));
  }
  void draw(float r, float g, float b){
  float mult = randomGaussian();
  r = r * mult;
  g = g * mult;
  b = b * mult;
    
   for(int i = 0; i < particleList.size(); i ++){
     mistParticle p = particleList.get(i);
     p.draw(r, g, b);
     
     if(!p.isAlive()){
       particleList.remove(i);
       spawnNewParticle();
     }
   }
  }
}

class mistParticle{

  float xPos;
  float yPos;
  float zPos;
  
  float lifespan;
  float treshold;
  float sphereSize;
  
  boolean isBooming;
  boolean isDecaying;
  public mistParticle(float x, float y, float z) {
    this.xPos = x;
    this.yPos = y;
    this.zPos = z;
    
    zPos = random(-1000, -100);
    sphereSize = random(5, 10);
    
    isBooming = true;
    isDecaying = false;
    lifespan = random(10, 60);
    treshold = random(100, 150);
  }
  
  void draw(float r, float g, float b){ 
    
    
    pushMatrix();
    fill(r, g, b ,lifespan);
    noStroke();
    translate(xPos, yPos, zPos);
    sphere(sphereSize);
    popMatrix();
    
    uptadePosition();
  }
  
  void uptadePosition(){
    if(isBooming){
      if(lifespan < treshold){
        lifespan += random(0.1, 0.8);
      }
      else {
        isDecaying = true;
        isBooming = false;
      }
    }
    else {
      lifespan -= random(0.2, 0.4);
    }
    
    xPos += random(-0.1, 0.1);
    yPos += random(-0.1, 0.1);
    zPos += 10;
    if(zPos > 100){
      zPos = -1000;
    }
  }
  
  boolean isAlive(){
    boolean result = true;
    if(lifespan < 0){
      result = false;
    }
    
    return result;
  }
}