Arrays. Getting separate arrays of bubbles to emit at x,y coordinates of array of moving objects.

edited March 10 in Library Questions

I am trying to get an array of rising bubbles to emit from two bouncing moving orb objects. In the past I was able to get it to work, but it only worked for one of the orbs no matter what I tried.

I have simplified the code so that bubbles emits at mouseX, mouseY coordinates. And I have reversed mouse to show a second bubble does actually emerge at the skewed coordinates.

Any idea where I'm going wrong here. I'd appreciate the tips. Been trying this all day. Many thanks.

int numberOfOrbs = 2;
Orb_Class[] many_Orbs = new Orb_Class[numberOfOrbs];

int numberOfBubbles = 30;
Bubble_Class[] many_Bubbles = new Bubble_Class[numberOfBubbles];

int timer;


void setup()
{
  size(600, 900);
  noStroke();
  smooth(); 

  for (int i=0; i<many_Bubbles.length; i++) 
  {
    many_Bubbles[i] = new Bubble_Class(random(width), height, 10, 1);
  }


  for (int i=0; i<many_Orbs.length; i++) 
  {
    many_Orbs[i] = new Orb_Class(64, random(4, 6), random(4, 6)); 
  }
}


void draw()
{
  background( 255 );  // erase the window to black  
  stroke( 255 );      // draw using a white stroke 

  if (millis() - timer >= 500) 
  {
    for (int i=0; i<many_Bubbles.length; i++) 
    {
      many_Bubbles[0] = new Bubble_Class(mouseX, mouseY, 10, 1);
      many_Bubbles[1] = new Bubble_Class(mouseY, mouseX, 10, 1);    
    }
    timer = millis();
  }

  for (int j=0; j<many_Orbs.length; j++) 
  {
    many_Orbs[j].display();
    many_Orbs[j].move(j);  
  }


  for (int i=0; i<many_Bubbles.length; i++) 
  {
    many_Bubbles[i].ascend();
    many_Bubbles[i].display();
  }
}



class Orb_Class
{  
  float radius;   // radius
  float x; 
  float y = random(300, 600); // location
  float xspeed, yspeed; // speed  
  float xtime;  
  float ytime;

  // Constructor
  Orb_Class(float tempR, float tempXt, float tempYt) 
  {
    radius = tempR;
    xspeed = tempXt;
    yspeed = tempYt;   
  }

  void move(int arrayIndex)    // Unused for the moment
  { 
    //xspeed = incomingKickOSC;
    x += xspeed; // Increment x
    y += yspeed; // Increment y

    // Check horizontal edges 
    if (x > width || x < 0) {
      //popsound[arrayIndex].rewind();
      //popsound[arrayIndex].play();      
      xspeed *= -1;
    }
    //Check vertical edges
    if (y > height || y < 0) {
      //popsound[arrayIndex].rewind();
      //popsound[arrayIndex].play();
      yspeed *= -1;
    }    
  }

  void display()
  {  
    fill(255, 0, 0);
    noStroke();
    ellipse(x, y, radius, radius);  
  }
}



class Bubble_Class 
{
  float diameter;
  float riseSpeed;
  boolean popped = false;
  float x, y;

  Bubble_Class(float tempX, float tempY, float tempD, float tempRs) {
    x = tempX;
    y = tempY;
    diameter = tempD;
    riseSpeed = tempRs;
  }

  void ascend() {
    y = y - riseSpeed;
    x = x + random(-2, 2);
  }

  void display() {
    if (!popped) {
      stroke(0);
      fill(127, 100);
      ellipse(x, y, diameter, diameter);
    }
  }
}

I have also tried to move code within the Orb_Class and failed. I think I need to be doing something like this but my efforts are failing:

  if (millis() - timer >= 500) 
  {
    for (int i=0; i<many_Bubbles.length; i++) 
    {
      for (int j=0; j<many_Orbs.length; j++)
      {    
        many_Bubbles[0] = new Bubble_Class(somehow_Access_Array_For_Orb_PosX[j], somehow_Access_Array_For_Orb_PosY[j], 10, 1);
      } 
    }
    timer = millis();
  }

Answers

  • edited March 4

    i think you could

           many_Bubbles[0] = new Bubble_Class(mouseX, mouseY, 10, 1);        many_Bubbles[1] = new Bubble_Class(mouseY, mouseX, 10, 1);         

    into the class and use x,y instead of mouseX,mouseY

  • Thanks for tip, Chrisir. I had done that already and same result. Only one ball will emit bubbles.

    int numberOfOrbs = 5;
    Orb_Class[] many_Orbs = new Orb_Class[numberOfOrbs];
    
    int numberOfBubbles = 30;
    Bubble_Class[] many_Bubbles = new Bubble_Class[numberOfBubbles];
    
    int timer;
    int x, y;
    int orbx, orby;
    
    void setup()
    {
      size(600, 900);
      noStroke();
      smooth(); 
    
      for (int i=0; i<many_Bubbles.length; i++) 
      {
        many_Bubbles[i] = new Bubble_Class(random(width), height, 10, 1);
      }
    
    
      for (int i=0; i<many_Orbs.length; i++) 
      {  
        many_Orbs[i] = new Orb_Class(64, random(4, 6), random(4, 6)); 
      }
    }
    
    
    
    
    void draw()
    {
      background( 255 );  // erase the window to black  
      stroke( 255 );      // draw using a white stroke 
    
      for (int j=0; j<many_Orbs.length; j++) 
      {
        many_Orbs[j].display();
        many_Orbs[j].move(j);  
      }
    
    
      for (int i=0; i<many_Bubbles.length; i++) 
      {
        many_Bubbles[i].ascend();
        many_Bubbles[i].display();
      }
    }
    
    
    class Orb_Class
    {  
      float radius;   // radius
      float orbx; 
      float orby; // = random(300, 600); // location
      float xspeed, yspeed; // speed  
      float xtime;  
      float ytime;
    
      // Constructor
      Orb_Class(float tempR, float tempXt, float tempYt) 
      {
        radius = tempR;
        xspeed = tempXt;
        yspeed = tempYt;   
      }
    
      void move(int arrayIndex)    // Unused for the moment
      { 
        //xspeed = incomingKickOSC;
        orbx += xspeed; // Increment x
        orby += yspeed; // Increment y
    
        // Check horizontal edges 
        if (orbx > width || orbx < 0) {
          //popsound[arrayIndex].rewind();
          //popsound[arrayIndex].play();      
          xspeed *= -1;
        }
        //Check vertical edges
        if (orby > height || orby < 0) {
          //popsound[arrayIndex].rewind();
          //popsound[arrayIndex].play();
          yspeed *= -1;
        } 
    
    
        if (millis() - timer >= 500) 
        {
          for (int i=0; i<many_Bubbles.length; i++) 
          {
            many_Bubbles[i] = new Bubble_Class(orbx, orby, 10, 1);
          } 
        timer = millis();
      }
    
      }
    
      void display()
      {  
        fill(255, 0, 0);
        noStroke();
        ellipse(orbx, orby, radius, radius);  
      }
    }
    
    
    class Bubble_Class 
    {
      float diameter;
      float riseSpeed;
      boolean popped = false;
      float bubblex, bubbley;
    
      Bubble_Class(float tempX, float tempY, float tempD, float tempRs) {
        bubblex = tempX;
        bubbley = tempY;
        diameter = tempD;
        riseSpeed = tempRs;
      }
    
      void ascend() {
        bubbley = bubbley - riseSpeed;
        bubblex = bubblex + random(-2, 2);
      }
    
      void display() {
        if (!popped) {
          stroke(0);
          fill(127, 100);
          ellipse(bubblex, bubbley, diameter, diameter);
        }
      }
    }
    
  • you start the for loop with 0

    instead try to monitor how many you put in the array and then say

    for ( int i=numBubbles; i<numBubbles+ 20

    numBubbles+= 20 ;

    make the array much bigger

    an arrayList instead of array would be easier - it works with .size() and .add(new Bubble....

    best when the bubles leave the screen to remove() them from arrayList

  • edited March 4

    I just started learning processing as well. I think you should initialize all the variables for best practice. Also,

      if (millis() - timer >= 500) 
      {
        for (int i=0; i<many_Bubbles.length; i++) 
        {
          many_Bubbles[0] = new Bubble_Class(mouseX, mouseY, 10, 1);
          many_Bubbles[1] = new Bubble_Class(mouseY, mouseX, 10, 1);    
        }
        timer = millis();
      }
    

    It's inside a for loop, but the index doesn't change. You're just re-writing that position in the index 30 times and not drawing anything until the loop that runs each frame goes through all the bubbles. The bubbles in the rest of the array are randomly populated and you're drawing and moving them all at the same time. You could use a naturally looping array and check if the bubble is off the screen or is the first time it has been called and set it's location back to the emitter x and y. That's how I would approach it.

    Also it's not a good idea to reference mouse locations in a for loop. Store the mouse location to another variable and use that in the for loop. If you want bubbles to spawn from another object, create an emitter class and reference it's x and y value in your bubble and orb objects. Or just make a global variable for the mouse position and use that in your objects.

    Also, are you coming from Daniel Shiffman tuts?

    ps. a super simple shortcut would be getting rid of those for loops and just use an increment variable in your draw function and spawn a bubble each frame. That way you can just pass the mouseX and mouseY location or wherever you want directly into the function when it's emitted. That's the easiest way to do it.

  • Thanks guys, and sorry but I really have no idea how to put into practice what you are suggesting. At this point my brain is not working. Perhaps someone could point to a working example of my scenario in action, if they know of one. Yes I have been following along with those tuts, BGADII. I'm looking through his tuts how and can't quite find what I need.

  • here is a version without ArrayList

    it will crash after some minutes / hours

    numBubbles is the current number of bubbles

    (numberOfBubbles is size of array)

    Chrisir

    //Orbs are big and red and spawn bubbles 
    
    int numberOfOrbs = 5;
    Orb_Class[] many_Orbs = new Orb_Class[numberOfOrbs];
    
    int numberOfBubbles = 1130;
    Bubble_Class[] many_Bubbles = new Bubble_Class[numberOfBubbles];
    
    int timer;
    int x, y;
    int orbx, orby;
    
    int numBubbles=0;  // !!!!!!!!!!!!!!!!!!!!!!!
    
    // -----------------------------------------------
    
    void setup()
    {
      size(600, 900);
      noStroke();
      smooth(); 
    
      for (int i=0; i<30; i++) 
      {                   // !!!!!!!!!!!!!!!!!!!!!!!    nothing happens here 
        //  many_Bubbles[i] = new Bubble_Class(random(width), height, 10, 1);
      }
    
    
      for (int i=0; i<many_Orbs.length; i++) 
      {  
        many_Orbs[i] = new Orb_Class(64, random(4, 6), random(4, 6));
      }
    }
    
    void draw()
    {
      background(  0, 0, 255 );  // erase the window to black  
      stroke( 255 );      // draw using a white stroke 
    
      for (int j=0; j<many_Orbs.length; j++) 
      {
        many_Orbs[j].display();
        many_Orbs[j].move(j);
      }
    
      for (int i=0; i<numBubbles; i++)  // !!!!!!!!!!!!!!!!!!!!!!!
      {
        many_Bubbles[i].ascend();
        many_Bubbles[i].display();
      }
    }
    
    // =====================================
    
    
    class Orb_Class {
    
      float radius;   // radius
      float orbx; 
      float orby = random(300, height-100); // location
      float xspeed, yspeed; // speed  
      float xtime;  
      float ytime;
    
      // Constructor
      Orb_Class(float tempR, float tempXt, float tempYt) 
      {
        radius = tempR;
    
        xspeed = tempXt;
        if (random(100)<50)xspeed *= -1; 
    
        yspeed = tempYt;
        if (random(100)<50)yspeed *= -1;
      }
    
      void move(int arrayIndex)    // Unused for the moment
      { 
        //xspeed = incomingKickOSC;
        orbx += xspeed; // Increment x
        orby += yspeed; // Increment y
    
        // Check horizontal edges 
        if (orbx > width || orbx < 0) {
          //popsound[arrayIndex].rewind();
          //popsound[arrayIndex].play();      
          xspeed *= -1;
        }
        //Check vertical edges
        if (orby > height || orby < 0) {
          //popsound[arrayIndex].rewind();
          //popsound[arrayIndex].play();
          yspeed *= -1;
        } 
    
    
        if (millis() - timer >= 500) 
        {
          for (int i=numBubbles; i<numBubbles+30; i++)  // !!!!!!!!!!!!!!!!!!!!!!!
          {
            many_Bubbles[i] = new Bubble_Class(orbx, orby, 10, 1);
          } 
          numBubbles+= 20 ;
          timer = millis();
        }
      }
    
      void display()
      {  
        fill(255, 0, 0);
        noStroke();
        ellipse(orbx, orby, radius, radius);
      }
    }
    
    // =====================================
    
    class Bubble_Class {
    
      float diameter;
      float riseSpeed;
      boolean popped = false;
      float bubblex, bubbley;
      color color1; 
    
      Bubble_Class(float tempX, float tempY, 
        float tempD, 
        float tempRs) {
        bubblex = tempX+random(-12, 12);
        bubbley = tempY+random(-12, 12);
        diameter = tempD;
        riseSpeed = tempRs + random(1, 3);
        color1=color(random(127, 256), random(70, 122));
      }
    
      void ascend() {
        bubbley = bubbley - riseSpeed;
        bubblex = bubblex ; // + random(-2, 2);
      }
    
      void display() {
        if (!popped) {
          // stroke(0);
          fill(color1);
          ellipse(bubblex, bubbley, diameter, diameter);
        }
      }
    }
    //
    
  • Thanks Chrisir. As you said, that crashes after around a minute when it gets to end of array. Only one red orb of the 5 emits bubbles? Maybe that was your intension and you just wanted to show the array method.

  • edited March 4 Answer ✓

    I decided to come up with my own solution, maybe it can help you out. Keep in mind I just started java/processing last week. My big problem is figuring out how to do things efficiently. There are a many things that could be improved here. Because I just reset the location back to the origin as soon as it leaves the screen eventually patterns will emerge. You can also make it a looping array instead of just running through a large array of particle objects. Also the speed of emission, movement, collisions etc. could be added. But I hope it just serves as one simple example for how arrays and loops work.

    View the result: https://gfycat.com/BigheartedMeaslyBeaver

    int index;
    int max;
    
    Effects blend;
    classyEmitters[] classy = new classyEmitters[2];
    Bubblies[] nenoo = new Bubblies[1000];
    
    void setup() {
      size(600, 600);
      blend = new Effects();
      classy[0] = new classyEmitters();
      classy[1] = new classyEmitters();
      for (int i = 0; i < nenoo.length; i++) {
        nenoo[i] = new Bubblies();
      }
    
      index = 0;
      max = 0;
    }
    
    void draw () {
      background(0);
      textSize(24);
      textAlign(CENTER, CENTER);
      fill(255);
      text(frameRate, width/2, height/2);
      if (index > 100 & index < nenoo.length) {
        max++;
      }
    
      classy[0].getSchwifty(width/2, height/2, 5, 10, 200);
      classy[1].getSchwifty(width/2, height/2, -5, 20, 100);
      for (int i = max; i< index; i++) {
        nenoo[i].moveBubblies();
        nenoo[i].showBubblies();
      }
      if (index < nenoo.length) {
        index++;
      }
    }
    
    class classyEmitters {
    
      int xprev;
      int yprev;
      int xcur;
      int ycur;
      int rotation;
    
      classyEmitters() {
    
        xprev=0;
        yprev=0;
        xcur=0;
        ycur=0;
        rotation=0;
      }
    
    
      void getSchwifty(int x, int y, int zoomZoom, float soBig, float soFar) {
    
        xcur= int(cos(radians(rotation))*soFar) + x;
        ycur = int(sin(radians(rotation))*soFar) + y;
        rotation = rotation + zoomZoom;
    
        drawEllipse(xcur, ycur, soBig);
        xprev = xcur;
        yprev = ycur;
      }
    
      void drawEllipse(float x, float y, float size) {
    
        blend.blender(3, xprev, x, yprev, y, size, 255, 255, 255, 5);
    
        fill(255);
    
        ellipse(xcur, ycur, size, size);
      }
    }
    
    class Effects {
    
      Effects() {
      }
    
      void blender(int a, float b, float c, float d, float e, float f, float g, float h, float ii, float j) {
        int Count = a + 1;
        float x1 = b;
        float x2 = c;
        float y1 = d;
        float y2 = e;
        float size = f;
        float R = g;
        float G = h;
        float B = ii;
        float Alpha = j;
        noStroke();
        for (int i = 1; i < Count; i++) {
          fill(R, G, B, i*Alpha);
          ellipse(x1+ (x2 - x1) * i/Count, y1 + (y2 - y1) * i/Count, size, size);
        }
      }
    }
    
    class Bubblies {
      boolean spawned = false;
      float x;
      float y;
      int which;
      Bubblies() {
        float x = 0;
        float y = 0;
        which = int(random(0, 2));
      }
    
      void moveBubblies() {
    
        if (!spawned || y < -5) {
          x = classy[which].xcur;
          y = classy[which].ycur;
          spawned = true;
        } else { 
          y -= 1;
          x += random(-2, 2);
        }
      }
    
      void showBubblies() {
    
        if (which == 0) {
          fill(40, 74, 20);
        } else {
          fill(50, 20, 60);
        }
        if (y > -5) {
          ellipse(x, y, 10, 10);
        }
      }
    }
    
  • edited March 4 Answer ✓

    here is a version with ArrayList since the number of bubbles varies so much.

    This version doesn't crash anymore. (The last one crashed because we were adding 30 bubbles every time to an array with only 1130 slots. And we didn't have a function to free slots with bubbles that already left the screen. We have that now.)

    note that the timer variable belongs into the orb class, I think. I fixed that.

    //Orbs are big and red and spawn bubbles (which are gray/white) 
    
    Orb_Class[] many_Orbs = new Orb_Class[5];
    ArrayList<Bubble_Class> many_Bubbles = new ArrayList();
    
    // -----------------------------------------------
    
    void setup() {
      size(600, 900);
      noStroke();
      smooth(); 
    
      for (int i=0; i<many_Orbs.length; i++) {  
        many_Orbs[i] = new Orb_Class(64, random(4, 6), random(4, 6));
      }
    }
    
    void draw() {
    
      background(  0, 0, 255 );  // erase the window to black  
    
      // display red orbs 
      for (int j=0; j<many_Orbs.length; j++) {
        many_Orbs[j].display();
        many_Orbs[j].move(j);
      }
    
      // move through ArrayList
      for (Bubble_Class b : many_Bubbles) {
        b.ascend();
        b.display();
      }//for 
    
      // to remove we must move backwards through the ArrayList
      for (int i=many_Bubbles.size()-1; i>=0; i--) {
        Bubble_Class b = many_Bubbles.get(i); 
        if (b.isDead)
          many_Bubbles.remove(i);
      }//for
      //
    }
    
    // =====================================
    
    class Orb_Class {
    
      float radius;   // radius
      float orbx; 
      float orby = random(300, height-100); // location
      float xspeed, yspeed; // speed  
      float xtime;  
      float ytime;
    
      int timer;
      int duration= int(random(900, 1600));  
    
      // Constructor
      Orb_Class(float tempR, float tempXt, float tempYt) 
      {
        radius = tempR;
    
        xspeed = tempXt;
        if (random(100)<50)xspeed *= -1; 
    
        yspeed = tempYt;
        if (random(100)<50)yspeed *= -1;
      }
    
      void move(int arrayIndex)    // Unused for the moment
      { 
        //xspeed = incomingKickOSC;
        orbx += xspeed; // Increment x
        orby += yspeed; // Increment y
    
        // Check horizontal edges 
        if (orbx > width || orbx < 0) {
          //popsound[arrayIndex].rewind();
          //popsound[arrayIndex].play();      
          xspeed *= -1;
        }
        //Check vertical edges
        if (orby > height || orby < 0) {
          //popsound[arrayIndex].rewind();
          //popsound[arrayIndex].play();
          yspeed *= -1;
        } 
    
        if (millis() - timer >= duration) 
        {
          int upperBound = int(random(30)); 
          for (int i=0; i<upperBound; i++) 
          {
            many_Bubbles.add( new Bubble_Class(orbx, orby, 10, 1) );
          } 
          timer = millis();
          duration=int(random(900, 1800));
        }
      }
    
      void display()
      {  
        fill(255, 0, 0); // red 
        noStroke();
        ellipse(orbx, orby, radius, radius);
      }
    }
    
    // =====================================
    
    class Bubble_Class {
    
      float diameter;
      float riseSpeed;
      boolean popped = false; // ???????????????
      float bubblex, bubbley;
      color color1; 
      boolean isDead=false; 
    
      Bubble_Class(float tempX, float tempY, 
        float tempD, 
        float tempRs) {
        bubblex = tempX+random(-12, 12);
        bubbley = tempY+random(-12, 12);
        diameter = tempD;
        riseSpeed = tempRs + random(1, 3);
        // white-ish with different opacity
        color1=color(random(127, 256), random(70, 256));
      }
    
      void ascend() {
        bubblex = bubblex ; // + random(-2, 2);
        bubbley = bubbley - riseSpeed;
        if (bubbley<-30)
          isDead=true;
      }
    
      void display() {
        if (!popped) {
          // stroke(0);
          fill(color1);
          ellipse(bubblex, bubbley, diameter, diameter);
        }
      }
    }
    //
    
  • Wow BGADII... that will take some studying indeed,And you're a beginner??? Thank you very much. I'm sure I can learn new ways of doing things... and it's there's certainly some inspiration in the code for some whacky labelling techniques ;)

    Chrisir, thank you. I have never used an array list before to be honest. This does the exactly the job I wanted.

    Gentelmen, I am indebted to you both. I really spent too much time on this and, by looking at both examples it's clear I was going in the wrong direction.

  • edited March 5 Answer ✓

    ... and it's there's certainly some inspiration in the code for some whacky labelling techniques

    I have a hard time coming up with sensible variable names so I just have fun with it. Better to keep entertained and when you look back on your code you can tell how frustrated you were by how bad the language gets.

    I tweaked it a bit and came up with a very questionable collision checking method (at least it works... lol). But it's all the same code with some small changes and additions as I posted. Pretty flexible. (not sure why gfycat always cuts off the beginning of my video)

    https://gfycat.com/DecimalFearfulDingo

    edit: and here it is with 3 colors/emitters:

    https://gfycat.com/LegalFeistyBluegill

    Added a gravity toggle:

    https://gfycat.com/OrderlyAdvancedArmadillo

    And finally I was able to give the particles a cloud like effect.

    I'm a total beginner in Java/processing, the thing I love about processing is you only need to know a few functions and then it's just your logic and time. Unfortunately the solutions I come up with at this point really verbose, I'm sure there are more efficient ways to do things. I'm about 1500 lines of code into coding my first game from scratch, started last week, which is actually the first script I started in processing.

    Have you heard the word of our lord an savior Daniel Shiffman? I literally just watched the first few videos in his series where he goes through the basic functions like arrays and objects and started coding my app. He's amazing.

  • Very very cool! The gravity up down is a great idea.... collision check even better. I'll look into a collision checking system.

    Yes, I also worship at the church of Schiffman :)

    Thanks again!

  • edited March 6

    https://gfycat.com/KindThoseBobolink

    Improved: https://gfycat.com/ForsakenAnimatedEasternnewt

    Based on your challenge, I think I came up with my own particle based smoke algorithm and I also came up with a way to render to what I'm calling "boxel" like objects which I might be able to use to improve performance in my app as well. This smoke is based off 500 particles, runs at 7fps. I can increase the speed by adjusting the sample size/ rate. The next step blending the boxels to improve the effect at lower sample sizes.

    I'll move this over here. It's been a learning experience for me as well. Thanks!

  • Crikey. This sounds even cooler again! Haha... you're thanking me???

  • edited March 10

    Hi again.

    I have worked a bit further on my inital patch by adding an array of swimming fish and some OSC connectivity for audio visual reactions. After some effort, OSC panning and other effects I added seem to work. Each orb now vibrates to it’s own separate audio loop playing from a MAX Msp patch.

    I have been attempting two things with the array of fish; #1 to vibrate and #2 change their color when either or both orbs plunge beneath the water. Again I seem to have hit a wall here. The fish only react to one orb, but not both at once. I can chose which orb by referring to its index number. I figured this should be pretty simple, according to everything else I have working similarly. I have tried the method that BGADII suggested with my first query, and several others, but to no avail.

    The array for the two orbs is proving problematic. It might seem a bit overkill, but the reason for that array is that I will eventually add many more orbs(sound sources). The script overall is becoming quite confusing. I have pulled it apart several times to solve issues.

    I'd be really grateful if anyone would share some tips on my fish issue... and also general ways to clean up this sketch?

    I have been looking at the native object/class examples in the processing examples folder, but I'm not sure what methods work best for classes with values that interconnect. I am worried that if the patch gets any bigger it'll become wildly confusing (to me;).

    Many thanks!

    import ddf.minim.*;
    Minim minim;
    AudioPlayer[] popsound; 
    import oscP5.*;
    import netP5.*;
    OscP5 oscP5;
    NetAddress myRemoteLocation;   // ************************************
    
    int numberOfOrbs = 2;
    
    float[] incomingKickOSC = new float[numberOfOrbs];  // declare OSC message variable
    
    Orb_Class[] many_Orbs = new Orb_Class[numberOfOrbs];
    ArrayList<Bubble_Class> many_Bubbles = new ArrayList();
    Fish_Class[] many_Fish = new Fish_Class[30];
    
    // Constant Environmental Variables
    float spaceHeight;
    float waterSurfaceHeight;
    float seaFloor;
    
    float orbFishProximityBounces = 0;
    float orbSpaceProximityBounces = 0; 
    
    //Fish Parameters
    float fishColor = 0;
    float fishHeight; 
    
    float radius;   
    
    // ------------------------------------------------------------------------------------------------ SETUP
    void setup() {
      size(1000, 800, P3D);
      noStroke();
      smooth(); 
    
      oscP5 = new OscP5(this,11100);                         // start oscP5, listening for incoming messages at port 11000 
      myRemoteLocation = new NetAddress("127.0.0.1",11000);  // SEND OSC messages to Max MSP   
    
      spaceHeight = (height/3);
      waterSurfaceHeight = (height/3)*2;   
      seaFloor = height;  
      fishHeight = ((height/6)*5);    
      popsound = new AudioPlayer[numberOfOrbs];  // ************************************
      minim = new Minim(this); 
    
      for (int i=0; i<many_Orbs.length; i++) {  
        many_Orbs[i] = new Orb_Class(64, random(4, 6), random(2, 4));
        popsound[i] = minim.loadFile("splash.mp3");
      }//for
    
      for (int i=0; i<many_Fish.length; i++) {
        many_Fish[i] = new Fish_Class(0, random(waterSurfaceHeight, seaFloor), random(1, 3)); 
      }//for      
    }//setup
    
    
    
    // ------------------------------------------------------------------------------------------------ DRAW
    void draw() {
      background(  0, 0, 255 );  // erase the window to black  
      lights();  
      line(0, waterSurfaceHeight, width, waterSurfaceHeight);
    
      for (int j=0; j<many_Orbs.length; j++) {   // display red orbs 
        many_Orbs[j].display(j);
        many_Orbs[j].move(j);
        many_Orbs[j].fishBounceAndColoredOrNot();
        many_Orbs[j].skyReverberatesSound();
        many_Orbs[j].underwaterFiltersSound();
        many_Orbs[j].panSoundsInMax();
      }//for
    
      for (int i=0; i<many_Fish.length; i++) {
        many_Fish[i].moveFish();
        many_Fish[i].displayFish();
      }//for 
    
      for (Bubble_Class b : many_Bubbles) { // move through ArrayList
        b.ascend();
        b.burstAtSurface();
        b.display();
      }//for 
    
      for (int i=many_Bubbles.size()-1; i>=0; i--) {  // to remove we must move backwards through the ArrayList
        Bubble_Class b = many_Bubbles.get(i); 
        //popsound[i] = minim.loadFile("pop.mp3");   
        if (b.isDead){
          many_Bubbles.remove(i);
        }//if
      }//for
    
      tint(255, 127);  // Display at half opacity  
      fill(0, 41, 158, 200);
      noStroke();
      rect(0, height-height/3, width, height/3);  // The Ocean  
    
    
      // ---------------------- SENDING OSC MESSAGES TO MAX MSP ----------------------------------------
      OscMessage myMessage = new OscMessage("/oscFromProcToMax");       
      myMessage.add(many_Orbs[0].mappedFreq); 
      myMessage.add(many_Orbs[1].mappedFreq); 
      myMessage.add(many_Orbs[0].mappedVerbLevel);                                         /// *****************!!!!!!!!!
      myMessage.add(many_Orbs[1].mappedVerbLevel); 
      myMessage.add(many_Orbs[0].panningLeftRight);                                                         
      myMessage.add(many_Orbs[1].panningLeftRight);  
      oscP5.send(myMessage, myRemoteLocation);   /* send the message */  
    }//Draw
    
    
     // ---------------------- RECEIVING OSC MESSAGES FROM MAX ----------------------------------------
     // Technique found at: http://www.technopagan.net/blog/tech/processing-osc/
    
    void oscEvent(OscMessage theOscMessage1) {
      if (theOscMessage1.addrPattern().equals("/oscAmp")) {
        if(theOscMessage1.checkTypetag("ff") == true){
          //println(theOscMessage1.typetag());
          for(int i=0; i < numberOfOrbs; i++)       {
            incomingKickOSC[i] = theOscMessage1.get(i).floatValue();    
          }//for
        }//if
      }//if
    }//draw
    
    
    
    
    // -------------------------------------------------------------------------------------------------- ORB CLASS
    
    class Orb_Class {
      float mappedFreq;        //OSC variables
      float mappedVerbLevel;   //OSC variables
      float panningLeftRight;  //OSC variables
    
      float orbx; 
      float orby = random(300, height-100); // location
      float xspeed, yspeed; // speed  
      float xtime;  
      float ytime; 
      int timer;
      int duration= int(random(900, 1600));  
    
      // Constructor
      Orb_Class(float tempR, float tempXt, float tempYt) {
        radius = tempR;
    
        xspeed = tempXt;
        if (random(100)<50){
          xspeed *= -1;
        }//if
    
        yspeed = tempYt;
        if (random(100)<50){
          yspeed *= -1;
        }//if
      }
    
    
      void move(int arrayIndex){ 
        orbx += xspeed; // Increment x
        orby += yspeed; // Increment y
    
        if (orbx > width || orbx < 0) { // Check horizontal edges 
          xspeed *= -1;   
        }//if
    
        if (orby > height || orby < 0) { // Check vertical edges
          yspeed *= -1;
        }//if 
    
        if (orby > height/2){
          if (millis() - timer >= duration) {
            int upperBound = int(random(30)); 
            for (int i=0; i<upperBound; i++) {
              many_Bubbles.add( new Bubble_Class(orbx, orby, 10, 1) );
            }//for 
            timer = millis();
            duration=int(random(100, 300));
          }//if
        }//if
    
        if (orby+radius <= waterSurfaceHeight){  //Splash sound as orbs breach surface
          popsound[arrayIndex].rewind();
          popsound[arrayIndex].play();      
        }//if     
      }//void move
    
    
      void display(int arrayIndex){  
        pushMatrix();
        translate(orbx, orby, 0);
        fill(255, 0, 0); 
        noStroke();  
        sphere(radius/2+(incomingKickOSC[arrayIndex]*200));
        popMatrix();
      }
    
    
      void panSoundsInMax(){
         panningLeftRight = map(orbx, 0, width, 0.2, 0.8);
      }
    
    
      void fishBounceAndColoredOrNot(){
        if (   ( orby > (waterSurfaceHeight+radius/2) )   ){
          fishColor = 255; 
          orbFishProximityBounces = 1; 
        }//if 
        else{
          fishColor = 0;
          orbFishProximityBounces = 0.01; 
        }//else
      }
    
    
      void underwaterFiltersSound(){  
        if (   (orby < (waterSurfaceHeight+radius/2)) && (orby > (waterSurfaceHeight-radius/2))   ) {  
          mappedFreq = map(orby, (waterSurfaceHeight+(radius/2)), (waterSurfaceHeight-(radius/2)), 0, 20000);
        }//if
      }
    
    
      void skyReverberatesSound(){
        if (   (orby > (spaceHeight-radius/2)) && (orby < (spaceHeight+radius/2))   )  {  
          mappedVerbLevel = map(orby, (spaceHeight-(radius/2)), (spaceHeight+(radius/2)), 0, -72.6);        
          //orbSpaceProximityBounces = map(orby, (spaceHeight-(radius/2)), (spaceHeight+(radius/2)), 1, 0); 
        }//if
      }
    }
    
    
    
    
    // -------------------------------------------------------------------------------------------------- BUBBLE CLASS 
    class Bubble_Class {
      float diameter;
      float riseSpeed;
      float bubblex, bubbley;
      color color1; 
      boolean isDead=false; 
    
      Bubble_Class(float tempX, float tempY, float tempD, float tempRs) {
        bubblex = tempX+random(-12, 12);
        bubbley = tempY+random(-12, 12);
        diameter = tempD;
        riseSpeed = tempRs + random(1, 3);
        color1=color(random(127, 256), random(70, 256));
      }
    
      void ascend() {
        bubbley = bubbley - riseSpeed;
        if (bubbley<-30){
          isDead=true;
        }//if
      }
    
      void burstAtSurface() {             // Burst the bubbles as they reach the surface
        if (bubbley < ((height/3)*2)+diameter) {
          isDead=true;
        }//if
      }  
    
      void display() {
        fill(color1);
        ellipse(bubblex, bubbley, diameter, diameter);
      }
    }
    
    
    
    
    // -------------------------------------------------------------------------------------------------- FISH CLASS
    class Fish_Class
    {
      float fishx;
      float fishHeightConstrained;
      float fishSpeed;
      float fishy;
    
      // Constructor
      Fish_Class(float tempXpos, float tempYpos,  float tempSpeed) {
        fishx = tempXpos; 
        fishSpeed = tempSpeed;
        fishy = tempYpos;
      }
    
    
      void moveFish() {
        fishx = fishx + fishSpeed;
    
        for (int i=0; i<numberOfOrbs; i++) {
          fishy = fishy + (random(-10,10)*(incomingKickOSC[i]*5*orbFishProximityBounces) );    /// *****************!!!!!!!!!
        }//for
    
        fishHeightConstrained = constrain(fishy, 900, 600);// + (random(-10,10)*orbProximityToFish);
    
        if (fishx > width) {
          fishx = 0;
        }//if
        if (fishy < waterSurfaceHeight) {
          fishy = 900; 
        }//if
      }//moveFish
    
    
      void displayFish() {
        fill(fishColor);
        triangle(fishx, fishy, fishx-20, fishy+8, fishx-20, fishy-5);   
        ellipse(fishx, fishy, random(20, 30), random(10, 15)) ;
      }
    }
    
    //
    
  • Phew. I think I have solved it, finally. I'll post my code shortly.

Sign In or Register to comment.