06MA4010991AP
Computer Game Design

Week 2

Class Concept (Object Oriented Programming)

Version 1

source

Basic version of ball movement.



float x;  //x position of the ball
float y;  //y position of the ball
float xSpeed;  //x speed of the ball
float ySpeed;  //y speed of the ball
 
void setup()
{
  size(320,240);
  x = random(0,width);
  y = random(0,height);
  xSpeed = random(-5,5);
  ySpeed = random(-5,5);
  smooth();
}
 
void draw()
{
  background(0);
   
  if(x < 0)  //if hit left wall
    xSpeed = abs(xSpeed);
  if(x > width)  //if hit right wall
    xSpeed = -abs(xSpeed);
  if(y < 0)  //if hit upper wall
    ySpeed = abs(ySpeed);
  if(y > height)  //if hit lower wall
    ySpeed = -abs(ySpeed);
     
  x += xSpeed; //update position
  y += ySpeed; //update position
   
  ellipse(x,y,40,40);
}


Version 2

source

Using array to implement many balls moving using same rule.



 
float[] x;  //array of x
float[] y;  //array of y
float[] xSpeed;  //array of x speed
float[] ySpeed;  //array of y speed
int numBalls;  //number of balls
 
void setup()
{
  size(320,240);
  numBalls = 100;
 
  x = new float[numBalls];  //initialize array
  y = new float[numBalls];  //initialize array
  xSpeed = new float[numBalls];  //initialize array
  ySpeed = new float[numBalls];  //initialize array
 
  for(int i=0;i<numBalls;i++)  //initialize values
  {
    x[i] = random(0,width);
    y[i] = random(0,height);
    xSpeed[i] = random(-5,5);
    ySpeed[i] = random(-5,5);
  }
  smooth();
}
 
void draw()
{
  background(0);
  for(int i=0;i<numBalls;i++)  //draw all balls
  {
    if(x[i] < 0)
 xSpeed[i] = abs(xSpeed[i]);
    if(x[i] > width)
 xSpeed[i] = -abs(xSpeed[i]);
    if(y[i] < 0)
 ySpeed[i] = abs(ySpeed[i]);
    if(y[i] > height)
 ySpeed[i] = -abs(ySpeed[i]);
    x[i] += xSpeed[i];
    y[i] += ySpeed[i];
 
    ellipse(x[i],y[i],40,40);
  }
}

Version 3

source

Create a class of Ball, and implement attributes into class.


Ball[] balls;  //array of balls
int numBalls;  //number of balls
 
void setup()
{
  size(320,240);
  numBalls = 100;
 
  balls = new Ball[numBalls];  //initialize array
 
  for(int i=0;i<numBalls;i++)  //initialize each element (Ball)
  {
    balls[i] = new Ball();
  }
  smooth();
}
 
void draw()
{
  background(0);
  for(int i=0;i<numBalls;i++)  //update balls
  {
    balls[i].draw();
  }
}




class Ball  //class of ball
{
  float x;  //x position
  float y;  //y position
  float xSpeed;  //x speed
  float ySpeed;  //y speed
  color col;  //color
  float ballSize;  //ball size
 
  Ball()  //constructor (initialize variables)
  {
    x = random(0,width);
    y = random(0,height);
    xSpeed = random(-5,5);
    ySpeed = random(-5,5);
    col = color(random(255),random(255),ra ndom(255));
    ballSize = random(20,40);
  }
 
  void draw()  //custom function
  {
    if(x < 0)
 xSpeed = abs(xSpeed);
    if(x > width)
 xSpeed = -abs(xSpeed);
    if(y < 0)
 ySpeed = abs(ySpeed);
    if(y > height)
 ySpeed = -abs(ySpeed);
 
    x += xSpeed;
    y += ySpeed;
 
    noStroke();
    fill(col);
    ellipse(x,y,ballSize,ballSize);
  }
}

 

Version 4

source

Using another path and microphone as input. FFT(Fast Fourier transform) converts analog sound into spectrum of volume in different frequencies, and here we use an average of the volume as input.



import krister.Ess.*;  //import ess library
 
Ball[] balls;
int numBalls;
AudioInput myInput;  //microphone input
FFT myFFT;  //fft analysis
 
float micLevel;  //sound level
 
void setup()
{
  size(320,240);
   
  Ess.start(this);  //initialize ess
  myInput=new AudioInput();  //initalize microphone
  myInput.start();  //start microphone
  myFFT=new FFT();  //initialize fft
   
  numBalls = 50;
 
  balls = new Ball[numBalls];
 
  for(int i=0;i<numBalls;i++)
  {
    balls[i] = new Ball();
  }
  smooth();
}
 
void draw()
{
  background(0);
  micLevel = myFFT.getLevel(myInput) * 50;  //analyze sound level and scale up
 
  for(int i=0;i<numBalls;i++)
  {
    balls[i].draw();
  }
}



class Ball
{
  float x;
  float y;
  float xSpeed;
  float ySpeed;
  color col;
  float ballSize;
  float xFactor;  //acceleration of X
  float yFactor;  //acceleration of Y
 
  Ball()
  {
    x = random(0,width);
    y = random(0,height);
    xSpeed = random(-5,5);
    ySpeed = random(-5,5);
    col = color(random(255),random(255),ra ndom(255));
    ballSize = random(20,60);
    xFactor = random(0.001,0.02);
    yFactor = random(0.001,0.02);
  }
 
  void draw()
  {
    //accelerate to center, affect by xFactor and yFactor
    xSpeed += (width/2-x) * xFactor;
    ySpeed += (height/2-y) * yFactor;
 
    //let mic level affect speed
    xSpeed += random(-micLevel,micLevel);  //reference to sound level
    ySpeed += random(-micLevel,micLevel);  //reference to sound level
 
    //reduce speed (friction)
    xSpeed *= 0.98;
    ySpeed *= 0.98;
 
    //update ball position
    x += xSpeed;
    y += ySpeed;
 
    noStroke();
    fill(col);
    ellipse(x,y,ballSize,ballSize);
  }
}


 

Version 5

source

Make use of OpenGL's addictive blending function to create glowing visual effect, and use sound file feed for input.



import processing.opengl.*;  //import processing opengl
import javax.media.opengl.*; //import java opengl (for extra functions)
import krister.Ess.*;
 
Ball[] balls;
int numBalls;
AudioInput myInput;
AudioChannel myChannel;  //using sound file as input feed
 
FFT myFFT;
 
PGraphicsOpenGL pgl;  //opengl renderer for processing
GL gl;  //opengl renderer in java
PImage flare;  //flare image
 
float micLevel;
 
void setup()
{
  size(320,240,OPENGL);
  Ess.start(this);
  //myInput=new AudioInput();
  //myInput.start();
  myChannel=new AudioChannel("song4.aif");  //load music file
  myChannel.play(Ess.FOREVER);  //loop music
  myFFT=new FFT();
   
  flare = loadImage("flare.png");  //load image
 
  numBalls = 200;
 
  balls = new Ball[numBalls];
 
  for(int i=0;i<numBalls;i++)
  {
    balls[i] = new Ball();
  }
  smooth();
}
 
void draw()
{
  background(0);
 
  pgl = (PGraphicsOpenGL) g;
  gl = pgl.gl;
  pgl.beginGL();  //start controlling java opengl
  gl.glEnable(GL.GL_BLEND);  // Turn on the blend mode
  gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE);  // Define the blend mode
  scale(2);  //compensate scale error
   
   
  micLevel = myFFT.getLevel(myChannel) *20;  //analyze sound channel instead of mic input
  println(micLevel);
 
  for(int i=0;i<numBalls;i++)
  {
    balls[i].draw();
  }
   
  pgl.endGL();  //stop controlling java opengl
}



class Ball
{
  float x;
  float y;
  float xSpeed;
  float ySpeed;
  color col;
  float ballSize;
  float xFactor;
  float yFactor;
 
  Ball()
  {
    x = random(0,width);
    y = random(0,height);
    xSpeed = random(-5,5);
    ySpeed = random(-5,5);
    colorMode(HSB);  //using HSB color space
    col = color(random(255),255,255);  //get high satuation colors
    ballSize = random(20,60);
    xFactor = random(0.01,0.04);
    yFactor = random(0.01,0.04);
  }
 
  void draw()
  {
    xSpeed += (width/2-x) * xFactor;
    ySpeed += (height/2-y) * yFactor;
 
    xSpeed += random(-micLevel,micLevel);
    ySpeed += random(-micLevel,micLevel);
 
    xSpeed *= 0.9;
    ySpeed *= 0.9;
 
 
    x += xSpeed;
    y += ySpeed;
 
    noStroke();
    //fill(col);
    //ellipse(x,y,ballSize,ballSize);
    tint(col);
    image(flare,x- ballSize/2,y - ballSize/2,ballSize,ballSize);
  }
}

Version 6

source

Create more forms of particles and using ArrayList for a variable number of particle.



import processing.opengl.*;
import javax.media.opengl.*;
import krister.Ess.*;
 
ArrayList balls;  //using ArrayList instead of array
int numBalls;
AudioInput myInput;
AudioChannel myChannel;
 
FFT myFFT;
PFont font;  //font
 
PGraphicsOpenGL pgl;
GL gl;
PImage flare;
PImage p1;  //CD cover image
 
float micLevel;
 
void setup()
{
  size(320,240,OPENGL);
  Ess.start(this);
  myChannel=new AudioChannel("song4.aif");
  myChannel.play(Ess.FOREVER);
 
  font = loadFont("font.vlw");  //load font
 
  myFFT=new FFT();
   
   
  flare = loadImage("flare.png");
  p1 = loadImage("p2.png");  //load cd cover image
 
  numBalls = 200;
 
  balls = new ArrayList();  //initialize ArrayList
  smooth();
}
 
void draw()
{
  background(0);
   
  pgl = (PGraphicsOpenGL) g;
  gl = pgl.gl;
  pgl.beginGL();
  gl.glEnable(GL.GL_BLEND);
  gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE);
  scale(2);
   
   
  micLevel = myFFT.getLevel(myChannel) *30;
   
  for(int j=0;j<micLevel/100;j++)  //add balls into array list
  {
    balls.add(new Ball()); //initialize a ball and put into array list
  }
 
  for(int i=0;i<balls.size();i++)  //update balls in array list
  {
    Ball b = (Ball)balls.get(i);  //fetch the ball from list
     
    if(b.life>0)
 b.draw();  //update ball
    else
    {
 balls.remove(i);  //remove ball from list
 i--;  //adjust the position of counter
    }
  }
   
  pgl.endGL();
}




class Ball
{
  float x;
  float y;
  float xSpeed;
  float ySpeed;
  color col;
  float ballSize;
  float xFactor;
  float yFactor;
  int life;  //life of ball (number of frames exist in canvas)
  int form;  //form of ball (different looking)
 
  Ball()
  {
    x = random(0,width);
    y = random(0,height);
    xSpeed = random(-5,5);
    ySpeed = random(-5,5);
    colorMode(HSB);
    col = color(random(255),255,255);
    ballSize = random(50,100);
    xFactor = random(0.01,0.04);
    yFactor = random(0.01,0.04);
 
    life = (int) random(30,70);
    form = (int) random(3);  //random form 3 modes
  }
 
  void draw()
  {
    life--;
    xSpeed += (width/2-x) * xFactor;
    ySpeed += (height/2-y) * yFactor;
 
    xSpeed += random(-micLevel,micLevel);
    ySpeed += random(-micLevel,micLevel);
 
    xSpeed *= 0.9;
    ySpeed *= 0.9;
 
 
    x += xSpeed;
    y += ySpeed;
 
    noStroke();
 
    if(form == 0)  //mode 0 for image of cd cover
    {
 tint(col);
 image(p1,x- ballSize/2,y - ballSize/2,life,life);
    }
    else if(form == 1)  //mode 1 for flare
    {
 tint(col);
 image(flare,x- ballSize/2,y - ballSize/2,ballSize,ballSize);
    }
    else if(form == 2)  //mode 2 for text (*)
    {
 fill(col);
 textFont(font);
 textAlign(CENTER);
 text("*",x,y);
    }
  }
}

Version 7

source

Convert the sketch into full screen application.



//full screen application script
static public void main(String args[]) {
  PApplet.main(new String[]  
  {  
    "--present","tutor_2_ball_v7"    
  }
  );
}
 
 
import processing.opengl.*;
import javax.media.opengl.*;
import krister.Ess.*;
 
ArrayList balls;
int numBalls;
AudioInput myInput;
AudioChannel myChannel;
 
FFT myFFT;
PFont font;
 
PGraphicsOpenGL pgl;
GL gl;
PImage flare;
PImage p1;
 
float micLevel;
 
void setup()
{
  size(screen.width,screen.height,OPENGL);  //using computer screen size
  Ess.start(this);
  myInput=new AudioInput();  
  myInput.start();
  myChannel=new AudioChannel("song4.aif");
  myChannel.play(Ess.FOREVER);
 
  font = loadFont("font.vlw");
 
  myFFT=new FFT();
 
 
  flare = loadImage("flare.png");
  p1 = loadImage("p2.png");
 
  numBalls = 200;
 
  balls = new ArrayList();
  smooth();
}
 
void draw()
{
  background(0);
 
  pgl = (PGraphicsOpenGL) g;
  gl = pgl.gl;
  pgl.beginGL();
  gl.glEnable(GL.GL_BLEND);
  gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE);
  scale(2);
 
 
  micLevel = myFFT.getLevel(myChannel) *100;
  for(int j=0;j<micLevel/10;j++)
  {
    balls.add(new Ball());  
  }
  println(micLevel);
 
  for(int i=0;i<balls.size();i++)
  {
    Ball b = (Ball)balls.get(i);
 
    if(b.life>0)
 b.draw();
    else
    {
 balls.remove(i);
 i--;
    }
 
  }
   
  fill(micLevel*20);
  textFont(font);
  textAlign(CENTER);
  text("RADIOHEAD - IN RAINBOWS",width/2,height/2);  //display text
   
  pgl.endGL();
 
   
}



class Ball
{
  float x;
  float y;
  float xSpeed;
  float ySpeed;
  color col;
  float ballSize;
  float xFactor;
  float yFactor;
  int life;
  int form;
 
  Ball()
  {
    x = random(0,width);
    y = random(0,height);
    xSpeed = random(-5,5);
    ySpeed = random(-5,5);
    colorMode(HSB);
    col = color(random(120,180),255,255);
    ballSize = random(150,300);
    xFactor = random(0.01,0.04);
    yFactor = random(0.01,0.04);
 
    life = (int) random(30,70);
    form = (int) random(3);
  }
 
  void draw()
  {
    life--;
    xSpeed += (width/2-x) * xFactor;
    ySpeed += (height/2-y) * yFactor;
 
    xSpeed += random(-micLevel,micLevel);
    ySpeed += random(-micLevel,micLevel);
 
    xSpeed *= 0.9;
    ySpeed *= 0.9;
 
 
    x += xSpeed;
    y += ySpeed;
 
    noStroke();
 
    if(form == 0)
    {
 tint(col);
 image(p1,x- ballSize/2,y - ballSize/2,life,life);
    }
    else if(form == 1)
    {
 tint(col);
 image(flare,x- ballSize/2,y - ballSize/2,ballSize,ballSize);
    }
    else if(form == 2)
    {
 fill(col);
 textFont(font);
 textAlign(CENTER);
 text("*",x,y);
    }
  }
}


Reference Videos


Murcof - Mir Nodes from Simon on Vimeo.



Mogwai - New Paths to Helicon Part II - Live Visuals from Simon on Vimeo.

Galaxy from flight404 on Vimeo.

Audio Reactive 3 from Stefan Goodchild on Vimeo.

Arcarsenal - Bones Mag Hardcore Test from Simon on Vimeo.

Music Is Math from Glenn Marshall on Vimeo.

Processing - Audio reactive Bubbles from moka on Vimeo.

the nerd side of life from moka on Vimeo.

Audio Reactive 2 from Stefan Goodchild on Vimeo.

Aphex Twin - Rhubarb from Simon on Vimeo.

Bodysnatchers - Zeno Music Visualiser from Glenn Marshall on Vimeo.

Magnetosphere revisited (audio by Tosca) from flight404 on Vimeo.

1969 from flight404 on Vimeo.

Solar, with lyrics. from flight404 on Vimeo.

Relentless, The REV from flight404 on Vimeo.