import ddf.minim.*; boolean cheats = false; /** * Game 23: "No more spheres!" - title by Pierrec
* Right-click to move, left-click to shoot.
*
* [attribution: bell sound by sandyrb]
*
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; boolean l_down; boolean r_down; 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; AudioPlayer bgm; AudioSample burstSound; AudioSample shotSound; AudioSample dieSound; AudioSample dingSound; void audioInit() { minim = new Minim(this); burstSound = minim.loadSample("burst.wav", 1024); shotSound = minim.loadSample("shot.wav", 1024); dieSound = minim.loadSample("die.wav", 1024); dingSound = minim.loadSample("ding.wav", 1024); bgm = minim.loadFile("deathtoll.mp3", 2048); bgm.loop(); } void audioClose() { burstSound.close(); shotSound.close(); dieSound.close(); dingSound.close(); bgm.close(); minim.stop(); } color TEXT_COLOR = color(128, 32, 0); float DEFAULT_SPHERE_RADIUS = 25; float DSR = DEFAULT_SPHERE_RADIUS; int SPHERE_HP = 10; int BLAST_LIFE = 60; float SPHERE_SPIN_RATE = 0.005; float SHOT_KICK = DEFAULT_SPHERE_RADIUS * 3 / SPHERE_HP; float PLAYER_ACCEL = 0.05; float PLAYER_TOP_SPEED = 3; float CONTROL_INNER_RADIUS = 10; float CONTROL_OUTER_RADIUS = 100; float PLAYER_TURN_RATE = 0.05; float SHOT_SPEED = 6; int AUTOFIRE_RATE = 15; int DEATH_DURATION = PHYSICS_FPS * 2; int CLEAR_DURATION = PHYSICS_FPS * 3; int INTRO_DURATION = PHYSICS_FPS * 1; ParticleList shrapnel; ArrayList bullets; ArrayList spheres; PVector player_pos; float player_speed; float player_angle; int autofire_timer; boolean player_alive; int level; int level_time; int game_time; int best_time; boolean time_counting; boolean victory; int death_countdown; int clear_countdown; int intro_countdown; void setup() { ellipseMode(RADIUS); size(600, 600); frameRate(600); audioInit(); font = loadFont("PressStartK-64.vlw"); loadLevel(0); } void loadLevel(int lev) { level = lev; shrapnel = new ParticleList(); bullets = new ArrayList(); spheres = new ArrayList(); player_pos = new PVector(width/2, height/2); player_angle = -HALF_PI; player_speed = 0; player_alive = true; time_counting = false; if(level > 0) time_counting = true; else game_time = 0; intro_countdown = INTRO_DURATION; level_time = 0; clear_countdown = 0; death_countdown = 0; victory = false; switch(level) { case 0: spheres.add(new Sphere(width*3/4, height/4)); break; case 1: spheres.add(new Sphere(width/2, height/4)); spheres.add(new YSphere(width/2, height*3/4)); spheres.add(new XSphere(width*3/4, height*3/4)); spheres.add(new RSphere(width*1/4, height*3/4)); break; case 2: spheres.add(new XSphere(width/2, height/2)); spheres.add(new YSphere(DSR, height/2)); spheres.add(new YSphere(width-DSR, height/2)); spheres.add(new RSphere(DSR, DSR)); spheres.add(new RSphere(width-DSR, DSR)); spheres.add(new RSphere(DSR, height-DSR)); spheres.add(new RSphere(width-DSR, height-DSR)); break; case 3: spheres.add(new RSphere(DSR, DSR)); spheres.add(new RSphere(width-DSR, DSR)); spheres.add(new RSphere(DSR, height-DSR)); spheres.add(new RSphere(width-DSR, height-DSR)); spheres.add(new RSphere(width/2, DSR)); spheres.add(new RSphere(DSR, height/2)); spheres.add(new RSphere(width/2, height-DSR)); spheres.add(new RSphere(width-DSR, height/2)); spheres.add(new RSphere(width/2, height/2)); break; case 4: Sphere cs = new CrossSphere(width/2, height/2); //cs.radius *= 1.3; spheres.add(cs); spheres.add(new YSphere(width*3/4, height/2)); spheres.add(new YSphere(width/4, height/2)); spheres.add(new XSphere(width/2, height*3/4)); spheres.add(new XSphere(width/2, height/4)); spheres.add(new Sphere(width-DSR, height/2)); spheres.add(new Sphere(DSR, height/2)); spheres.add(new Sphere(width/2, height-DSR)); spheres.add(new Sphere(width/2, DSR)); break; case 5: float DSR2 = DSR * 2; spheres.add(new CrossSphere(DSR2, DSR2)); spheres.add(new CrossSphere(width-DSR2, DSR2)); spheres.add(new CrossSphere(DSR2, height-DSR2)); spheres.add(new CrossSphere(width-DSR2, height-DSR2)); spheres.add(new XSphere(width/2, DSR2)); spheres.add(new YSphere(DSR2, height/2)); spheres.add(new XSphere(width/2, height-DSR2)); spheres.add(new YSphere(width-DSR2, height/2)); spheres.add(new RSphere(width/2, height/2)); break; case 6: for(int i = 0; i <= 12; i++) { spheres.add(new XSphere(DSR, height*i/12)); spheres.add(new XSphere(width-DSR, height*i/12)); } break; case 7: Sphere rs = new RSphere(width/2, height/2); rs.hp = 1; spheres.add(rs); spheres.add(new CrossSphere(width*3/4, height*1/3)); spheres.add(new CrossSphere(width/4, height*2/3)); spheres.add(new CrossSphere(width*2/3, height*3/4)); spheres.add(new CrossSphere(width/3, height/4)); spheres.add(new Sphere(width-DSR, height-DSR)); spheres.add(new Sphere(DSR, height-DSR)); spheres.add(new Sphere(width-DSR, DSR)); spheres.add(new Sphere(DSR, DSR)); break; default: victory = true; break; } } void stop() { audioClose(); super.stop(); } void physicsStep() { if(intro_countdown > 0) intro_countdown --; if(time_counting && intro_countdown == 0 && !victory) { level_time ++; game_time ++; } if(!player_alive) { death_countdown --; time_counting = false; if(death_countdown <= 0) loadLevel(level); } if(spheres.isEmpty() && shrapnel.isEmpty() && player_alive && clear_countdown == 0 && !victory) { clear_countdown = CLEAR_DURATION; if(!muted) dingSound.trigger(); } if(clear_countdown > 0) { time_counting = false; clear_countdown --; if(clear_countdown <= 0) loadLevel(level+1); } //do controls if(player_alive && intro_countdown == 0 && !victory) { PVector mouse_pos = new PVector(mouseX, mouseY); PVector steer_delta = PVector.sub(mouse_pos, player_pos); float to_angle = atan2(steer_delta.y, steer_delta.x); player_angle = angleTowards(player_angle, to_angle, PLAYER_TURN_RATE); float distan = steer_delta.mag(); float target_speed = map(distan, CONTROL_INNER_RADIUS, CONTROL_OUTER_RADIUS, 0, PLAYER_TOP_SPEED); target_speed = max(0, target_speed); target_speed = min(PLAYER_TOP_SPEED, target_speed); if(r_down && distan > CONTROL_INNER_RADIUS) ;//target_speed = PLAYER_TOP_SPEED; else target_speed = 0; if(abs(target_speed - player_speed) < PLAYER_ACCEL) player_speed = target_speed; else if(player_speed < target_speed) player_speed += PLAYER_ACCEL; else if(player_speed > target_speed) player_speed -= PLAYER_ACCEL; player_pos.x += cos(player_angle) * player_speed; player_pos.y += sin(player_angle) * player_speed; if(player_pos.x < 0) player_pos.x = 0; if(player_pos.y < 0) player_pos.y = 0; if(player_pos.x > width) player_pos.x = width; if(player_pos.y > height) player_pos.y = height; autofire_timer--; if(l_down && autofire_timer <= 0) { bullets.add(new Shot(player_pos, player_angle)); autofire_timer = AUTOFIRE_RATE; if(!muted) shotSound.trigger(); } } Iterator bi = bullets.iterator(); while(bi.hasNext()) { Shot b = (Shot) bi.next(); b.tick(); if(b.out()) bi.remove(); else { Iterator si = spheres.iterator(); while(si.hasNext()) { Sphere s = (Sphere) si.next(); if(inRadius(s.pos, b.pos, s.radius)) { s.hp --; if(s.hp > 0) { s.pos.x += cos(b.angle)* SHOT_KICK; s.pos.y += sin(b.angle)* SHOT_KICK; } bi.remove(); //TODO hit sound break; } } } //TODO collision } Iterator si = spheres.iterator(); while(si.hasNext()) { Sphere s = (Sphere) si.next(); s.tick(); if(s.hp <= 0) { si.remove(); s.die(); if(!muted) burstSound.trigger(); } } shrapnel.tick(); } void drawingStep() { if(death_countdown > 0) //camera shake { float SHAKE_SCALE = 0.1; translate(SHAKE_SCALE*(random(death_countdown)-death_countdown/2), SHAKE_SCALE*(random(death_countdown)-death_countdown/2)); } background(blendColors(color(48, 0, 0), TEXT_COLOR, intro_countdown * 1.0/INTRO_DURATION)); noFill(); stroke(blendColors(color(0), TEXT_COLOR, intro_countdown * 1.0/INTRO_DURATION)); int GRIDSIZE = 50; for(int x = 0; x < width; x+=GRIDSIZE) line(x, 0, x, height); for(int y = 0; y < height; y+=GRIDSIZE) line(0, y, width, y); String more_spheres; int count = spheres.size(); if(count == 0) more_spheres = "No more spheres!"; else if(count == 1) more_spheres = "1 more sphere"; else more_spheres = ""+count+" more spheres"; if(!player_alive) more_spheres = "..."; textFont(font, 32); textAlign(CENTER, CENTER); fill(blendColors(TEXT_COLOR, color(255), clear_countdown * 1.0/ CLEAR_DURATION)); text(more_spheres, width/2, height/2); if(level > 0) { textAlign(CENTER, TOP); String time_text = ""; if(victory) time_text = "Final Time: "; time_text += game_time / PHYSICS_FPS; time_text += "."; String decimal = ""+(game_time * 100 / PHYSICS_FPS)%100; if(decimal.length() < 2) decimal += "0"; time_text += decimal; text(time_text, width/2, 8); textAlign(LEFT, TOP); textFont(font, 16); if(!victory) text("Level "+level, 8, 8); else { textAlign(CENTER, TOP); text("click to play again", width/2, 48); textAlign(RIGHT, BOTTOM); text("v1.0", width-8, height-8); } } else { textAlign(RIGHT, CENTER); textFont(font, 16); fill(blendColors(TEXT_COLOR, color(255), clear_countdown * 1.0/ CLEAR_DURATION)); if(clear_countdown == 0) text("shoot this ", width*3/4 - 30, height/4); else text("begin", width*3/4 - 30, height/4); } //draw blasts shrapnel.draw(); //draw spheres Iterator si = spheres.iterator(); while(si.hasNext()) { Sphere s = (Sphere) si.next(); s.draw(); } //draw bullets Iterator bi = bullets.iterator(); while(bi.hasNext()) { Shot b = (Shot) bi.next(); b.draw(); } //draw player if(player_alive && intro_countdown == 0 && !victory) { strokeWeight(1); fill(255, 255, 96); noStroke(); float pradius = 17; pushMatrix(); translate(player_pos.x, player_pos.y); beginShape(); vertex(cos(player_angle)*pradius, sin(player_angle)*pradius); vertex(cos(player_angle+TWO_PI*2/5)*pradius, sin(player_angle+TWO_PI*2/5)*pradius); vertex(0, 0); vertex(cos(player_angle-TWO_PI*2/5)*pradius, sin(player_angle-TWO_PI*2/5)*pradius); endShape(CLOSE); popMatrix(); } } 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) bgm.mute(); else bgm.unmute(); } if(theKey == 'P' && !title) paused = !paused; if(cheats && theKey == '=') loadLevel(level+1); } void up(int theKey) { println(theKey + " up"); } void mousePressed() { if(mouseButton == LEFT) l_down = true; if(mouseButton == RIGHT) r_down = true; if(victory && intro_countdown == 0) loadLevel(0); } void mouseReleased() { if(mouseButton == LEFT) l_down = false; if(mouseButton == RIGHT) r_down = false; }