• fullscreen
  • Boule.pde
  • Sonoboules.pde
  • class Boule {
      float posX, posY;
      float velX, velY;
      float radius = BOULE_RADIUS;
      float strength = 0;
      int multi;
      Oscillator osc;
      
      Boule(float x, float y, int multi) {
        this.posX = x;
        this.posY = y;
        this.multi = multi;
      }
      
      void setVelocity(float speed, float direction) {
        velX = speed * cos(direction);
        velY = speed * sin(direction);
      }
    
      float getSpeed() {
        return sqrt(velX * velX + velY * velY);
      }
      
      float getDirection() {
        return atan2(velY, velX);
      }
      
      float getTransparency(float r) {
        return (r < radius) ? 0 : (r < radius + 1) ? r - radius : 1;
      }
      
      float speedFactor(float s, float theta) {
        return cos(getDirection() - theta) * getSpeed() / s;
      }
      
      boolean collidesWith(Boule other) {
        return dist(this.posX, this.posY, other.posX, other.posY) <= this.radius + other.radius;
      }
      
      void update(float dt) {
    
        // Update position
        posX += velX * dt;
        posY += velY * dt;
    
        // Check for collision with left/right edge
        if (posX < radius) {
          posX = 2 * radius - posX;
          velX = -velX;
        }
        else if (posX >= width - radius) {
          posX = 2 * (width - radius) - posX;
          velX = -velX;
        }
    
        // Check for collision with top/bottom edge
        if (posY < radius) {
          posY = 2 * radius - posY;
          velY = -velY;
        }
        else if (posY >= height - radius) {
          posY = 2 * (height - radius) - posY;
          velY = -velY;
        }
    
        // Recalculate strength
        float decay = BOULE_ATTEN * strength * exp(-dt);
        if (strength > decay)
          strength -= decay;
        else
          strength = 0;
    
        // Update oscillator amplitude
        osc.setAmp(VOLUME * strength / multi);
      }
    }
    
    import ddf.minim.*;
    import ddf.minim.signals.*;
    
    static final float VOLUME = 0.05;
    static final float BRIGHTNESS = 0.1;
    
    static float BOULE_RADIUS = 24;
    static float BOULE_SPEED = 120;
    static float BOULE_ATTEN = 0.05;
    
    static final float F = 110; // Fundamental frequency
    
    int[] multis = { 3, 4, 6, 8, 9, 12 };
    Boule[] boules = new Boule[multis.length];
    
    float t; // Time of last update, in seconds
    
    Minim minim;
    AudioOutput out;
      
    void setup() {
      size(640, 480);
    
      minim = new Minim(this);
      out = minim.getLineOut(Minim.STEREO);
    
      for (int i = 0; i < boules.length; i++) {
        boules[i] = new Boule(random(width), random(height), multis[i]);
        boules[i].setVelocity(BOULE_SPEED, random(TWO_PI));
        boules[i].osc = new SineWave(F * multis[i], 0, out.sampleRate());
        out.addSignal(boules[i].osc);
      }
    
      t = millis() * 1e-3;
    }
    
    void draw() {
      
      // Apply motion update
      float tt = millis() * 1e-3;
      for (int i = 0; i < boules.length; i++)
        boules[i].update(tt - t);
      t = tt;
      
      // Check for collisions
      for (int i = 0; i < boules.length; i++) {
        for (int j = i + 1; j < boules.length; j++) {
          if (boules[i].collidesWith(boules[j])) {
            // Calculate offset
            float dx = boules[j].posX - boules[i].posX;
            float dy = boules[j].posY - boules[i].posY;
            // Calculate distance and angle
            float s = sqrt(dx * dx + dy * dy);
            float theta = atan2(dy, dx);
            // Calculate speed factors
            float p = boules[j].speedFactor(s, theta) - boules[i].speedFactor(s, theta);
            // Update speeds
            boules[i].velX += p * dx;
            boules[i].velY += p * dy;
            boules[j].velX -= p * dx;
            boules[j].velY -= p * dy;
            // Adjust strength
            boules[i].strength += abs(p);
            boules[j].strength += abs(p);
            // Shift first object away from second, so they don't keep colliding
            float q = (boules[i].radius + boules[j].radius) / s - 1;
            boules[i].posX -= q * dx;
            boules[i].posY -= q * dy;
          }
        }
      }
      
      // Draw display
      loadPixels();
      for (int y = 0; y < height; y++) {
        int y_offset = y * width;
        for (int x = 0; x < width; x++) {
          float vis = 1;
          float value = 0;
          for (int i = 0; i < boules.length; i++) {
            float r = dist(x, y, boules[i].posX, boules[i].posY);
            value += BRIGHTNESS * sq(boules[i].radius / r)  * boules[i].strength;
            float z = r - boules[i].radius;
            vis *= (z < 0) ? 0 : (z < 1) ? z : 1;
          }
          pixels[y_offset + x] = color(0xff * vis * value);
        }
      }
      updatePixels();
    }
    
    void stop() {
      out.close();
      minim.stop();
      super.stop();
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Report Sketch

    Report for inappropriate content

    Please provide details if possible:

    Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

    Make a Copyright Infringement claim

    Michael Groufsky
    CgRobot
    14 Nov 2012
    This is really cool! Nice job.
    Very nice one, thanks for sharing.
    ale plus+
    6 Aug 2013
    Really nice!
    You need to login/register to comment.