import ddf.minim.*; /** * Game 22: "Fifty Stars"
* Set off chain reactions to earn combo points.
*
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; 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"); }