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!
* Creative Commons License
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"); }