import ddf.minim.*;
/**
* Game 22: "Fifty Stars"
* Set off chain reactions to earn combo points.
*
Go play more games at NMcCoy.net!
* 
This work by Nathan McCoy is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
*/
boolean[] keys = new boolean[256];
boolean title;
boolean paused;
boolean muted;
int drawing_ms_last;
int physics_ms_last;
int CORE_FPS = 540;
int DRAWING_FPS = 60;
int PHYSICS_FPS = 180;
int DRAW_MS = 1000 / DRAWING_FPS;
int PHYS_MS = 1000 / PHYSICS_FPS;
Minim minim;
PFont font;
int draw_frame;
int phys_frame;
float STAR_DESCEND = 0.25;
float STAR_DRAG = 0.99;
float STAR_RADIUS = 20;
int STAR_RATE = 220;
float STAR_POP_MINSPEED = 0.5;
float POP_RADIUS = 75;
float BURST_RADIUS = 75;
int BURST_COOLDOWN = 60;
float BURST_KICK = 0.018;
int BURST_LIFE = 30;
int TRAIL_LIFE = 260;
int burst_timer;
int APPLAUSE_TIME = 180;
int applause_timer;
int star_counter;
int MAX_STARS = 50;
color[] COLORS = {color(255, 0, 0), color(255, 255, 0), color(255, 0, 255), color(0, 255, 0), color(0, 255, 255)};
AudioSample burstSound;
AudioSample popSound;
AudioSample bonusSound;
AudioSample bonus2Sound;
AudioSample bonus3Sound;
AudioSample applauseSound;
void audioInit()
{
minim = new Minim(this);
burstSound = minim.loadSample("burst.wav", 1024);
popSound = minim.loadSample("fireworks2.wav", 1024);
bonusSound = minim.loadSample("bonus.wav", 1024);
bonus2Sound = minim.loadSample("bonus2.wav", 1024);
bonus3Sound = minim.loadSample("bonus3.wav", 1024);
applauseSound = minim.loadSample("applause.wav", 1024);
}
void audioClose()
{
burstSound.close();
popSound.close();
bonusSound.close();
bonus2Sound.close();
bonus3Sound.close();
applauseSound.close();
minim.stop();
}
ArrayList stars;
ParticleList bursts;
ParticleList trails;
int score;
int topscore;
boolean impressive;
void newGame()
{
draw_frame = 0;
phys_frame = 0;
burst_timer = 0;
score = 0;
star_counter = 0;
impressive = false;
}
void setup()
{
size(480, 480);
frameRate(600);
audioInit();
newGame();
font = loadFont("Century-26.vlw");
star_counter = MAX_STARS;
stars = new ArrayList();
bursts = new ParticleList();
trails = new ParticleList();
}
void stop()
{
audioClose();
super.stop();
}
void physicsStep()
{
topscore = max(score, topscore);
phys_frame++;
bursts.tick();
trails.tick();
if(burst_timer > 0) burst_timer --;
if(applause_timer > 0)
{
applause_timer --;
color c = COLORS[(int)random(COLORS.length)];
if(phys_frame%3 == 0) bursts.add(new BurstLeader(new PVector(random(width), random(height)), new PVector(random(2)-1, -2), c));
}
if(phys_frame % STAR_RATE == 0 && star_counter < MAX_STARS)
{
stars.add(new Star());
star_counter ++;
}
Iterator si = stars.iterator();
boolean busy = false;
while(si.hasNext())
{
Star s = (Star)si.next();
s.tick();
if(s.pos.y > height+STAR_RADIUS && s.life>0) si.remove();
else if(s.life <= 0 && s.vel.mag() < STAR_POP_MINSPEED)
{
s.pop();
si.remove();
}
if(s.life <= 0) busy = true;
}
if(!busy && impressive)
{
if(!muted) applauseSound.trigger();
applause_timer = APPLAUSE_TIME;
impressive = false;
}
}
void drawingStep()
{
background(0, 0, 64);
Iterator si = stars.iterator();
textFont(font, 26);
fill(255, 160);
textAlign(RIGHT, TOP);
text("Top: "+topscore, width-5, 5);
textAlign(LEFT, TOP);
if(!(stars.isEmpty() && star_counter == MAX_STARS))
text("Score: "+score+"\n"+star_counter+"/"+MAX_STARS, 5, 5);
else
{
text("Score: "+score, 5, 5);
fill(255);
textAlign(CENTER, CENTER);
text("Fifty Stars\n\n[click to begin]", width/2, height/2);
}
bursts.draw();
trails.draw();
while(si.hasNext())
{
Star s = (Star)si.next();
s.draw();
}
textFont(font);
if(applause_timer > 0)
{
fill(255, 2*255*applause_timer/APPLAUSE_TIME);
textAlign(CENTER, CENTER);
text("Spectacular!", width/2, height/2);
}
if(paused)
{
noStroke();
fill(0, 128);
rect(0, 0, width, height);
fill(255);
textAlign(CENTER, CENTER);
text("[Paused]", width/2, height/2);
}
}
void burst(float x, float y, float r, int g)
{
int BURST_BITS = 12;
color c = COLORS[(int)random(COLORS.length)];
for(int i = 0; i < BURST_BITS; i++)
{
float angle = i * TWO_PI / BURST_BITS;
PVector v = new PVector(cos(angle)*r/BURST_LIFE, sin(angle)*r/BURST_LIFE);
bursts.add(new BurstLeader(new PVector(x, y), v, c));
}
if(g > 0)
trails.add(new NumberDust(new PVector(x, y), c, g));
Iterator si = stars.iterator();
PVector burst_center = new PVector(x, y);
while(si.hasNext())
{
Star s = (Star)si.next();
if(inRadius(s.pos, burst_center, r + STAR_RADIUS))
{
PVector away = PVector.sub(s.pos, burst_center);
away.normalize();
away.mult(BURST_KICK * r *(1 + random(0.1)));
s.vel = away;
s.life-= 3;
s.gen = g;
}
}
}
void draw()
{
cursor(CROSS);
while(physics_ms_last + PHYS_MS < millis())
{
if(!paused)
{
physicsStep();
}
physics_ms_last += PHYS_MS;
}
if(drawing_ms_last + DRAW_MS < millis())
{
drawingStep();
drawing_ms_last = millis();
}
}
void mousePressed()
{
if(burst_timer <= 0 && !paused)
{
burst(mouseX, mouseY, BURST_RADIUS, 0);
if(!muted) burstSound.trigger();
burst_timer = BURST_COOLDOWN;
if(stars.isEmpty() && star_counter == MAX_STARS) newGame();
}
}
void keyPressed()
{
if(!keys[keyCode])
{
keys[keyCode] = true;
down(keyCode);
}
}
void keyReleased()
{
if(keys[keyCode])
{
keys[keyCode] = false;
up(keyCode);
}
}
void down(int theKey)
{
println(theKey + " down");
if(theKey == 'M') muted = !muted;
if(theKey == 'P' && !(stars.isEmpty() && star_counter == MAX_STARS)) paused = !paused;
}
void up(int theKey)
{
println(theKey + " up");
}