import moviemaker.*;
//import processing.opengl.*;
import procontroll.*;
import net.java.games.input.*;
import traer.physics.*;
import krister.Ess.*;
/**
Click in the applet and press any key to start a game
Use the arrow keys for movement, 'a' for the sucking force, 's' for the blowing force
'g' to turn on the glow, but expect a performace hit
*/
// ----------- GAME SETTINGS ----------------- //
int playerSize = 35; // radius in pixels
float playerSpeed = 12; // move amount in pixels per frame TODO: make this time based
color playerColor = color(255);
color playerGlow = color(254, 215, 96);
float nestSize = 110; // radius in pixels
color nestColor = color(255);
color nestGlow = color(254, 215, 96);
int kickInterval = 5; // spawn a kick pulser every #th kick
int kickRadius = 31; // in pixels
float kickMass = 1f;
color kickColor = color(255, 237, 102);
color kickGlow = color(255, 162, 0);
int snareInterval = 5; // spawn a snare pulser every #th snare
int snareRadius = 23; // in pixels
float snareMass = 1.5f;
color snareColor = color(255, 150, 79);
color snareGlow = color(255, 0, 0);
int hatInterval = 5; // spawn a hat pulser every #th hat
int hatRadius = 17; // in pixels
float hatMass = 2f;
color hatColor = color(198, 254, 183);
color hatGlow = color(0, 234, 255);
int pickUpRadius = 20;
color pickUpColor = color(121, 255, 151);
color pickUpGlow = color(0, 255, 30);
int bumpMax = 10; // the maximum number of times a bumper will give points before despawning
color skullColor = color(254, 229, 13);
color skullGlow = color(0, 255, 156);
color sbColor = color(253, 0, 126);
color sbGlow = color(255, 0, 255);
float pulseAmt = 1.3f; // percentage of how much larger they will get
int maxPulsers = 20; // maximum number of pulsers allowed on screen
float glowIntensity = 200;
float suckStrength = 3f; // larger number means stronger sucking
float blowStrength = 75f; // larger number means stronger blowing
int maxEnemies = 3;
// ------------------- END GAME SETTINGS ----------------------- //
PFont arial;
PImage[] words = new PImage[16];
PS2Controller gamepad;
ParticleSystem phys = new ParticleSystem(0, .2f);
Events evnt = new Events();
Player pl;
Pulser puls;
Vector pulsers = new Vector(20, 10);
Nest nest;
PickUp pick;
Deathskull skull;
Vector skulls = new Vector(maxEnemies, 0);
Sucker sucker;
Vector suckers = new Vector(maxEnemies, 0);
Blower blower;
Vector blowers = new Vector(maxEnemies, 0);
Bumper bump;
Vector bumpers = new Vector(3, 0);
AudioInput in;
BeatDetect beat;
Countdown count;
MovieMaker mm;
int kickWait = 0;
int snareWait = 0;
int hatWait = 0;
int totalCaught = 0;
ScoreDisplayer score;
int playTimer = 0;
boolean capture = false;
boolean makeMovie = false;
boolean record = false;
boolean debug = false;
boolean screenStats = true;
boolean playing = false;
boolean pause = false;
boolean drawGlow = true;
boolean drawGhost = false;
boolean useGamepad = false;
boolean time = false;
int timer = 0;
void setup()
{
// setup the environment
size(1024, 768, P3D);
background(0);
noCursor();
//smooth();
ellipseMode(CENTER_RADIUS);
frameRate(30);
arial = loadFont("ArialMT-24.vlw");
textFont(arial);
words[0] = loadImage("0.png");
words[1] = loadImage("1.png");
words[2] = loadImage("2.png");
words[3] = loadImage("3.png");
words[4] = loadImage("4.png");
words[5] = loadImage("5.png");
words[6] = loadImage("6.png");
words[7] = loadImage("7.png");
words[8] = loadImage("8.png");
words[9] = loadImage("9.png");
words[10] = loadImage("minus.png");
words[11] = loadImage("glee.png");
words[12] = loadImage("go.png");
words[13] = loadImage("pulsers_saved.png");
words[14] = loadImage("score.png");
words[15] = loadImage("timeout.png");
if ( useGamepad )
{
// setup the gamepad
gamepad = new PS2Controller(this);
gamepad.leftStick.setMultiplier(playerSpeed);
gamepad.leftStick.setTolerance(0.3f);
gamepad.rightStick.setTolerance(0.15f);
gamepad.invertRightY = true;
}
// create the player
pl = new Player();
// create the nest
nest = new Nest();
// create the countdown
count = new Countdown(3);
// create the score displayer
score = new ScoreDisplayer();
// setup the sound
Ess.start(this);
in = new AudioInput(1024, 44100);
beat = new BeatDetect(in.size, in.sampleRate);
beat.detectMode("FREQ_ENERGY");
beat.detectDetail(64);
in.start();
if ( makeMovie ) mm = new MovieMaker(this, width, height, "kish.mov", MovieMaker.VIDEO, MovieMaker.LOW, 30);
}
void draw()
{
if ( pause )
{
delay(5000);
pause = false;
}
if ( !playing && ( keyPressed || ( useGamepad && gamepad.Start.pressed() ) ) )
{
phys.clear();
pulsers.clear();
suckers.clear();
blowers.clear();
skulls.clear();
bumpers.clear();
pick = null;
nest = new Nest();
pl = new Player();
totalCaught = 0;
score.reset();
playTimer = millis();
playing = true;
count.start();
}
if ( count.running )
{
background(10, 0, 23);
count.update();
}
else
{
if ( drawGhost ) { fill(10, 0, 23, 90); rect(0, 0, width, height); }
else background(10, 0, 23);
game();
if ( playing && playTime() > 180000 )
{
fill(10, 0, 23, 128);
rect(0, 0, width, height);
image(words[15], 10, 100);
image(words[13], 10, 250, words[13].width/2, words[13].height/2);
printNumber(totalCaught, 500, 260, 0.5, 0);
image(words[14], 10, 330, words[14].width/2, words[14].height/2);
printNumber(score.total(), 500, 320, 0.5, 0);
playing = false;
pl.reset();
pause = true;
}
}
if ( capture && frameCount%300 == 0 ) saveFrame("kish-####.png");
if ( makeMovie && record )
{
loadPixels();
mm.addFrame(pixels, width, height);
}
}
void game()
{
phys.tick();
evnt.update();
// play timer in background
if ( playing )
{
int timeLeft = 180000 - playTime();
int minutes = timeLeft / 60000;
int seconds = (timeLeft - minutes*60000) / 1000;
printNumber(minutes, -300, 200, 3, 70);
if ( seconds > 9 ) printNumber(seconds, 250, 200, 3, 70);
else
{
printNumber(0, 45, 200, 3, 70);
printNumber(seconds, 250, 200, 3, 70);
}
}
// Update the player
if ( playing )
{
if ( useGamepad )
{
pl.move(gamepad.leftX(), gamepad.leftY());
pl.suck( gamepad.X.pressed() );
pl.blow( gamepad.O.pressed(), beat.isKick() );
}
else
{
pl.keyMove();
pl.keySuck();
pl.keyBlow(beat.isKick());
}
}
// make new pulsers from beat if there are fewer than maxPulsers on the board
if ( pulsers.size() < maxPulsers )
{
if ( beat.isKick() )
{
if ( kickWait == 0 )
{
if ( debug ) println("Adding a kick.");
float x = random(kickRadius, width-kickRadius);
float y = random(kickRadius, height-kickRadius);
while ( nest.isVisible() && dist(nest.x(), nest.y(), x, y) < nestSize + kickRadius )
{
x = random(kickRadius, width-kickRadius);
y = random(kickRadius, height-kickRadius);
}
pulsers.add(new Pulser(KICK, x, y));
kickWait = kickInterval;
}
else kickWait--;
}
if ( beat.isSnare() )
{
if ( snareWait == 0 )
{
if ( debug ) println("Adding a snare.");
float x = random(snareRadius, width-snareRadius);
float y = random(snareRadius, height-snareRadius);
while ( nest.isVisible() && dist(nest.x(), nest.y(), x, y) < nestSize + snareRadius )
{
x = random(snareRadius, width-snareRadius);
y = random(snareRadius, height-snareRadius);
}
pulsers.add(new Pulser(SNARE, x, y));
snareWait = snareInterval;
}
else snareWait--;
}
if ( beat.isHat() )
{
if ( hatWait == 0 )
{
if ( debug ) println("Adding a hat.");
float x = random(hatRadius, width-hatRadius);
float y = random(hatRadius, height-hatRadius);
while ( nest.isVisible() && dist(nest.x(), nest.y(), x, y) < nestSize + hatRadius )
{
x = random(hatRadius, width-hatRadius);
y = random(hatRadius, height-hatRadius);
}
pulsers.add(new Pulser(HAT, x, y));
hatWait = hatInterval;
}
else hatWait--;
}
}
// make new pickups every 30 seconds
if ( pick == null && playTime() > 59000 && playTime() % 30000 < 200 )
{
pick = new PickUp();
println("Made a pickup");
}
// manage pickup
if ( pick != null && pick.isDead() ) pick = null;
if ( pick != null )
{
pick.update();
pick.interact(pl);
if ( pick.isFree() ) pl.interact(pick);
pick.render();
}
// manage the nest
nest.update();
if ( nest.isVisible() )
{
if ( beat.isKick() ) nest.spawnRing();
if ( pick != null ) nest.tryCatch(pick);
}
else if ( nest.hiddenFor() > 3 && bumpers.size() == 0 )
{
boolean found = false;
for (int i = 0; !found && i < 5; i++)
{
found = true;
nest.move();
// test for overlap with skulls
for (int j = 0; found && j < skulls.size(); j++)
{
skull = (Deathskull)skulls.get(j);
if ( dist(nest.x(), nest.y(), skull.x(), skull.y()) < nest.radius() + skull.radius() ) found = false;
}
for (int j = 0; found && j < suckers.size(); j++)
{
sucker = (Sucker)suckers.get(j);
if ( dist(nest.x(), nest.y(), sucker.x(), sucker.y()) < nest.radius() + sucker.radius() ) found = false;
}
for (int j = 0; found && j < blowers.size(); j++)
{
blower = (Blower)blowers.get(j);
if ( dist(nest.x(), nest.y(), blower.x(), blower.y()) < nest.radius() + blower.radius() ) found = false;
}
for (int j = 0; found && j < bumpers.size(); j++)
{
bump = (Bumper)bumpers.get(j);
if ( dist(nest.x(), nest.y(), bump.x(), bump.y()) < nest.radius() + bump.radius() ) found = false;
}
for (int j = 0; found && j < pulsers.size(); j++)
{
puls = (Pulser)pulsers.get(j);
if ( dist(nest.x(), nest.y(), puls.x(), puls.y()) < nest.radius() + puls.radius() ) found = false;
}
}
if ( found ) nest.show();
}
// make new deathskull, maybe
if ( skulls.size() + suckers.size() + blowers.size() < maxEnemies && prob(1) )
{
skulls.add(new Deathskull());
}
// manage the deathskulls
for (int i = 0; i < skulls.size(); i++)
{
skull = (Deathskull)skulls.get(i);
if ( skull.isOffScreen() ) skull.kill();
if ( skull.isDead() ) skulls.remove(i--);
else
{
pl.interact(skull);
skull.update();
skull.render();
}
}
// make a new sucker/blower, maybe
if ( skulls.size() + suckers.size() + blowers.size() < maxEnemies && prob(1) )
{
suckers.add(new Sucker());
}
// manage the suckers
for (int i = 0; i < suckers.size(); i++)
{
sucker = (Sucker)suckers.get(i);
if ( sucker.isOffScreen() ) sucker.kill();
if ( sucker.isDead() ) suckers.remove(i--);
else
{
pl.interact(sucker);
sucker.update();
sucker.render();
}
}
if ( skulls.size() + suckers.size() + blowers.size() < maxEnemies && prob(1) )
{
blowers.add(new Blower());
}
// manage the blowers
for (int i = 0; i < blowers.size(); i++)
{
blower = (Blower)blowers.get(i);
if ( blower.isOffScreen() ) blower.kill();
if ( blower.isDead() ) blowers.remove(i--);
else
{
pl.interact(blower);
blower.update();
blower.render();
}
}
// manage bumpers
for (int i = 0; i < bumpers.size(); i++)
{
bump = (Bumper)bumpers.get(i);
if ( bump.isDead() ) bumpers.remove(i--);
else
{
for (int j = 0; j < skulls.size(); j++) bump.interact((Deathskull)skulls.get(j));
for (int j = 0; j < suckers.size(); j++) bump.interact((Sucker)suckers.get(j));
for (int j = 0; j < blowers.size(); j++) bump.interact((Blower)blowers.get(j));
bump.interact(pl);
bump.update();
bump.render();
}
}
if ( time ) timer = millis();
// pulsing, nest interaction, player interaction, enemy interaction,
// collision and rendering
for (int i = 0; i < pulsers.size(); i++)
{
puls = (Pulser)pulsers.get(i);
// do all the stuff that doesn't require interaction
if ( puls.isDying() ) { puls.render(); puls.deathTick(); continue; }
if ( puls.isDead() ) { pulsers.remove(i--); continue; }
puls.update();
// pulse according to type
switch(puls.type)
{
case KICK: if ( beat.isKick() ) puls.pulse(); break;
case SNARE: if ( beat.isSnare() ) puls.pulse(); break;
case HAT: if ( beat.isHat() ) puls.pulse(); break;
}
// collide with other pulsers
for (int j = i+1; j < pulsers.size(); j++) puls.interact( (Pulser)pulsers.get(j) );
// interact with player
if ( puls.isFree() ) pl.interact(puls);
puls.interact(pl);
// interact with the nest
if ( nest.isVisible() ) nest.tryCatch(puls);
// interact with enemies
for (int j = 0; j < skulls.size(); j++)
{
skull = (Deathskull)skulls.get(j);
puls.interact(skull);
if ( skull.awareOf(puls) ) skull.target(puls);
}
for (int j = 0; j < suckers.size(); j++)
{
sucker = (Sucker)suckers.get(j);
puls.interact(sucker);
if ( sucker.isSucking() && sucker.awareOf(puls) ) sucker.interact(puls);
}
for (int j = 0; j < blowers.size(); j++)
{
blower = (Blower)blowers.get(j);
puls.interact(blower);
if ( blower.isBlowing() && blower.awareOf(puls) ) blower.interact(puls);
}
for (int j = 0; j < bumpers.size(); j++)
{
bump = (Bumper)bumpers.get(j);
bump.interact(puls);
}
if ( puls.isOnWall() ) puls.wallBounce();
puls.render();
}
if ( time ) println(frameCount + ": managing pulsers took " + (millis()-timer));
if ( nest.isVisible() ) nest.render();
pl.render();
if ( playing )
{
image(words[13], 500, 0, words[13].width/2, words[13].height/2);
printNumber(totalCaught, 890, 5, 0.5, 0);
score.display();
}
if ( screenStats )
{
fill(255, 0, 0);
textFont(arial);
textSize(24);
textAlign(LEFT);
text("Frame Rate: " + frameRate, 5, height - 35);
text("Total pulsers: " + pulsers.size(), 5, height - 15);
}
if ( debug )
{
println(Runtime.getRuntime().freeMemory());
println("End draw, frame " + frameCount);
}
}
int playTime()
{
return millis() - playTimer;
}
void printNumber(int n, float x, float y, float sc, int fadeAmt)
{
float spacing = 70*sc;
String num = str(n);
if ( n < 0 ) tint(255, 0, 0, 255 - fadeAmt*3);
else tint(255, 255, 255, 255 - fadeAmt*3);
for (int i = num.length()-1; i >= 0; i--)
{
int nInd = parseInt(num.charAt(i))-48;
if ( nInd == -3 )
{
PImage tmp = words[10];
image(tmp, x + spacing*3.2 + (i-num.length())*spacing, y + 30*sc, tmp.width*sc, tmp.height*sc);
}
else
{
PImage tmp = words[nInd];
image(tmp, x + spacing*3 + (i-num.length())*spacing, y, tmp.width*sc, tmp.height*sc);
}
}
noTint();
}
boolean prob(int p)
{
return millis() % 100 < p;
}
void keyPressed()
{
if ( key == CODED )
{
switch(keyCode)
{
case UP:
pl.up = true;
break;
case RIGHT:
pl.right = true;
break;
case DOWN:
pl.down = true;
break;
case LEFT:
pl.left = true;
break;
}
}
else
{
if ( key == 'a' ) pl.suck = true;
else if ( key == 's' ) pl.blow = true;
else if ( key == 'g' ) drawGlow = !drawGlow;
else if ( key == 'h' ) drawGhost = !drawGhost;
else if ( key == 'r' && makeMovie ) record = true;
else if ( key == 't' && makeMovie ) { record = false; mm.finishMovie(); }
else if ( key == '1' ) evnt.trigger(0);
else if ( key == '2' ) evnt.trigger(1);
else if ( key == '3' ) evnt.trigger(2);
else if ( key == '4' ) evnt.trigger(3);
else if ( key == '5' ) evnt.trigger(4);
else if ( key == '6' ) evnt.trigger(5);
}
}
void keyReleased()
{
if ( key == CODED )
{
switch(keyCode)
{
case UP:
pl.up = false;
break;
case RIGHT:
pl.right = false;
break;
case DOWN:
pl.down = false;
break;
case LEFT:
pl.left = false;
break;
}
}
else
{
if ( key == 'a' ) pl.suck = false;
else if ( key == 's' ) pl.blow = false;
}
}
public void audioInputData(AudioInput in)
{
beat.detect(in);
}
public void stop()
{
Ess.stop();
super.stop();
}