Skip to content

Instantly share code, notes, and snippets.

@FreedomGrenade
Created April 3, 2015 11:04
Show Gist options
  • Save FreedomGrenade/a4a8b12c9a53d6c4450f to your computer and use it in GitHub Desktop.
Save FreedomGrenade/a4a8b12c9a53d6c4450f to your computer and use it in GitHub Desktop.
Whistle High notes or low notes to move the paddle.
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
Minim minim;
AudioInput input;
FFT fft;
int max, min;
float lowFrequency = 900; // change these if the frequency is uncomfortable to maintain or has a bias to one side
float highFrequency = 2000;
float cutOff = 10.0; // or try lowering this
Paddle pad;
Ball ball;
int mode = 0;
int waittime = 0;
float lowVal, highVal;
boolean wait = false;
boolean ready = false;
public void setup() {
size(500, 500);
minim = new Minim(this); // minim stuff
input = minim.getLineIn(Minim.MONO, 2048);
fft = new FFT(input.bufferSize(), input.sampleRate() );
fft.window(FFT.HAMMING);
min = fft.freqToIndex(lowFrequency);
max = fft.freqToIndex(highFrequency);
menuSetup();
}
public void draw() {
fft.forward(input.mix);
float n = highestPeak();
switch (mode) {
case 0 :
menuScreen(n);
break;
case 1 :
gameScreen(n);
break;
case 2 :
gameOverScreen();
break;
default :
exit();
}
}
public void gameScreen(float n) {
background(128+n*64, 128-n*64, 192);
if (waittime <= millis() || pad.dead) { // current time has passed the wait time
pad.update(n); // display if paddle is dead, because I used the wait time to delay the gameOver also
ball.update();
}
ball.display();
pad.display();
if (pad.dead) {
if (waittime <= millis()) {
background(0);
endGame();
} else {
fill(0, 255 - (waittime - millis())*255/1000); // fade out
rect(0, 0, width, height);
}
}
}
public void menuSetup() {
wait = false;
lowVal = 0;
highVal = 0;
}
public void gameKill() {
if (!pad.dead) {
pad.killMe();
wait = true;
waittime = millis() + 2000;
}
}
public void menuScreen(float n) {
background(0);
if (lowVal < height && n < -0.2) lowVal+=10;
if (highVal < height && n > 0.2) highVal+=10;
noStroke();
fill(64, 192, 192);
rect(0, height, width*0.5, -lowVal);
fill(192, 64, 192);
rect(width*0.5, height, width*0.5, -highVal);
fill(255);
textSize(30);
textAlign(CENTER, CENTER);
text("Hold a high whistle then a low whistle", 0, 0, width, height);
if (lowVal >= height && highVal >= height) startGame();
}
public void gameOverScreen() {
background(0);
if (waittime <= millis()) { // current time has passed the wait time
startGame();
} else { // display message if still waiting
fill(255);
textSize(30);
textAlign(CENTER, CENTER);
text("You've failed everyone", 0, 0, width, height);
}
}
public void startGame() {
wait = true;
waittime = millis() + 1000;
pad = new Paddle(width*0.5, height -20);
ball = new Ball(width*0.5, height*0.5, (int)random(2.0)*2-1, 1);
mode = 1;
}
public void endGame() {
wait = true;
waittime = millis() + 3000;
mode = 2;
}
public void ballPaddleCollision(Ball b, Paddle p) {
float relx = b.x - p.x;
float rely = b.y - p.y;
boolean d0 = (rely < relx * p.ph/p.pw); // positions over/under diagonals
boolean d1 = (rely < -relx * p.ph/p.pw);
if (d0 & d1) b.y = p.y-p.ph-b.rad; // top
if (d0 & !d1) b.x = p.x+p.pw+b.rad; // right
if (!d0 & d1) b.x = p.x-p.pw-b.rad; // left
if (d0 ^ d1) { // under one, over the other (ball is 'beside' the paddle
b.xv = -b.xv;
} else {
if (d0 & d1) b.yv = -b.yv*1.5; // bounce and increase only if ball is above
}
}
public class Ball {
float x, y, xv, yv;
float rad = 20;
public Ball(float x, float y, float xv, float yv) {
this.x = x;
this.y = y;
this.xv = xv;
this.yv = yv;
}
public void update() {
x+=xv;
y+=yv;
if (x < rad || x >= width - rad) {
xv=-xv;
x+=xv;
}
if (y < rad) {
yv=-yv;
y+=yv;
}
if (y > height) gameKill();
if (pad.collideWith(x, y, rad)) ballPaddleCollision(this, pad);
}
public void display() {
noStroke();
fill(255);
ellipse(x, y, rad*2, rad*2);
}
}
public class Paddle {
float x, xv, y, yv;
int pw = 40;
int ph = 10;
boolean dead;
public Paddle(float x, float y) {
this.x = x;
this.y = y;
xv = 0;
yv = 0;
dead = false;
}
public void killMe() {
dead = true;
yv = -20;
}
public void update(float pos) {
if (dead) { // if dead , bump off the screen
yv=yv+1;
y+=yv;
} else { // move normally
xv+=pos;
xv*=0.9;
x+=xv;
if (x < pw || x >= width-pw) { // simple bounce for paddle on walls
x=constrain(x, pw, width-pw-1);
xv=-xv*0.5;
}
}
}
public boolean collideWith(float xb, float yb, float rb) {
return (xb >= x-pw-rb && xb <= x+pw+rb && yb >= y-ph-rb && yb <= y+ph+rb);
}
public void display() {
noStroke();
fill(255);
rect(x-pw, y-ph, pw*2, ph*2);
}
}
public float highestPeak() { // find highest peak
boolean set = false;
int num = 0;
float highest = 0;
for (int i = min; i <= max; i++) {
float t = fft.getBand(i);
boolean r0 = (fft.getBand(i+1)-t) >= 0;
boolean r1 = (t-fft.getBand(i-1)) >= 0;
if (r1 != r0) { // if the slopes are different this is a peak or valley
if (highest < t || !set) { // check if it's the highest peak
highest = t;
num = i;
}
set = true;
}
}
if (highest >= cutOff && set) return map(num, min, max, -1, 1); // map num to left or right
return 0; // nothing valid,
}
public void stop() {
minim.stop();
input.close();
super.stop();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment