import ddf.minim.*;
/**
* Game 25: "More lovely and more temperate"
* Click and drag to collect chains of matching flowers.
*
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;
float TENSION = 0.0008;
float DRAG = 0.985;
int TRAIL_LIFE = 60;
float COMBO_DRAIN = 0.5/PHYSICS_FPS;
float MAX_COMBO = 3.4;
float MARGIN = 60;
int FLOWER_RIPEN = 180;
float FLOWER_RADIUS = 30;
int NUM_FLOWERS = 9;
color[] COLORS = {color(0, 200, 64), color(255, 255, 0), color(0, 255, 255), color(255, 192, 192)};
GameList flowers;
int score;
int flowercount;
int flowertype;
float combo;
PFont font;
int lastpoints;
int score_effect_timer;
int SCORE_EFFECT_TIME = 360;
ParticleList mote_trails;
ParticleList bursts;
PVector mote_pos;
PVector mote_vel;
PVector burst_pos;
int nextflower;
int lives;
int topscore = 0;
int MAX_LIVES = 10;
boolean tracing;
AudioSample burstSound;
AudioSample weakSound;
AudioSample hitSound;
AudioSample getSound;
AudioPlayer music;
void audioInit()
{
minim = new Minim(this);
getSound = minim.loadSample("get.wav", 1024);
getSound.setGain(-8);
hitSound = minim.loadSample("hit.wav", 1024);
burstSound = minim.loadSample("burst.wav", 1024);
weakSound = minim.loadSample("weakburst.wav", 1024);
music = minim.loadFile("iambic.mp3", 2048);
music.loop();
}
void audioClose()
{
getSound.close();
hitSound.close();
burstSound.close();
weakSound.close();
music.close();
minim.stop();
}
void setup()
{
size(720, 480);
frameRate(600);
audioInit();
mote_trails = new ParticleList();
bursts = new ParticleList();
flowers = new GameList();
font = loadFont("ARBERKLEY-48.vlw");
newGame();
}
void newGame()
{
lives = MAX_LIVES;
score = 0;
flowers.clear();
nextflower = 0;
tracing = false;
}
void stop()
{
audioClose();
super.stop();
}
void mousePressed()
{
if(lives> 0)
{
if(!tracing && !paused)
{
tracing = true;
mote_pos = new PVector(mouseX, mouseY);
mote_vel = new PVector(0, 0);
flowercount = 0;
flowertype = 0;
combo = 0;
}
}
else
newGame();
}
void physicsStep()
{
score_effect_timer --;
if(mousePressed)
{
}
else
{
if(tracing)
{
traceRelease();
}
}
if(tracing)
{
float offx = mouseX - mote_pos.x;
float offy = mouseY - mote_pos.y;
mote_vel.x += offx * TENSION;
mote_vel.y += offy * TENSION;
mote_vel.mult(DRAG);
mote_pos.add(mote_vel);
mote_trails.add(new Trail(COLORS[flowertype], mote_pos));
combo -= COMBO_DRAIN;
if(combo < 0) combo = 0;
}
mote_trails.tick();
bursts.tick();
while(flowers.size() < NUM_FLOWERS) flowers.add(new Flower());
flowers.tick();
}
void traceRelease()
{
tracing = false;
if(flowertype == 0) return;
lastpoints = (int)(flowercount * combo);
score_effect_timer = SCORE_EFFECT_TIME;
score += lastpoints;
topscore = max(score, topscore);
//TODO poof
burst_pos = new PVector(mote_pos.x, mote_pos.y);
if(burst_pos.x < MARGIN) burst_pos.x = MARGIN;
if(burst_pos.y < MARGIN) burst_pos.y = MARGIN;
if(burst_pos.x > width- MARGIN) burst_pos.x = width-MARGIN;
if(burst_pos.y > height - MARGIN) burst_pos.y = height-MARGIN;
if(combo > 0)
{
float initialAngle = atan2(mote_vel.y, mote_vel.x);
for(int i = 0; i < flowercount; i++)
{
float angle = initialAngle + i * TWO_PI / flowercount;
float enthusiasm = lastpoints * 0.3 + 1;
bursts.add(new Burst(COLORS[flowertype], mote_pos, new PVector(cos(angle)*enthusiasm, sin(angle)*enthusiasm)));
}
if(lastpoints >=15) if(!muted) burstSound.trigger();
if(lastpoints <15 && lastpoints > 0) if(!muted) weakSound.trigger();
}
if(flowertype != 0) lives--;
flowertype = 0;
}
void drawingStep()
{
background(COLORS[0]);
if(tracing)
{
fill(blendColors(COLORS[0], COLORS[flowertype], 0.3));
stroke(blendColors(COLORS[0], COLORS[flowertype], 0.15));
strokeWeight(3);
ellipse(mote_pos.x, mote_pos.y, combo * flowercount * 2, combo * flowercount * 2);
fill(blendColors(COLORS[0], color(255), 0.3));
noStroke();
strokeWeight(1);
textFont(font);
int hunds = (int)((combo - (int)combo)*100);
textAlign(CENTER, CENTER);
//text(""+flowercount+" x "+(int)combo+"."+hunds, width/2, height/2);
}
fill(blendColors(COLORS[0], color(255), 0.3));
noStroke();
textFont(font, 24);
textAlign(LEFT, TOP);
if(score != topscore && lives > 0) text(""+topscore, 8, 48);
fill(255);
noStroke();
ellipseMode(RADIUS);
flowers.draw();
mote_trails.draw();
fill(color(255));
noStroke();
textFont(font);
textAlign(LEFT, TOP);
if(lives > 0)
text(""+score, 8, 8);
else
{
textAlign(CENTER, CENTER);
text(""+score, width/2, height/2);
}
textAlign(LEFT, BASELINE);
text(" ", 0, height-8);
fill(255);
for(int i = 0; i < lives; i++)
{
if(i == lives-1 && flowertype != 0) fill(COLORS[flowertype]);
text(".");
}
textAlign(CENTER, CENTER);
if(score_effect_timer > 0)
{
fill(255, 255*score_effect_timer/(float)SCORE_EFFECT_TIME);
text("+"+lastpoints, burst_pos.x, burst_pos.y);
}
}
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 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(muted) music.mute();
else music.unmute();
}
//if(theKey == 'P' && !title) paused = !paused;
}
void up(int theKey)
{
println(theKey + " up");
}