/** * Game 09: "Squidfold"
* Arrows move
* Z to brighten
* X to darken
*
* (m = mute)
* Creative Commons License
This work by Nathan McCoy is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. */ import ddf.minim.*; import ddf.minim.effects.*; import ddf.minim.signals.*; AudioOutput out; Minim minim; BandPass bpf; PinkNoise pn; ArrayList stuff; boolean[] keys = new boolean[256]; int MAXDAM = 40; int BREAKDAM = 30; int breaks; int RECOVER = 8; float PACE = 2; float BASE_RATE = 0.03; float ACCEL_FACTOR = 0.000002 * PACE; float SPEED_BASE = 1.5; float SPEED_RATE = 0.0005 * PACE; float SIZE_BASE = 70; float SIZE_RATE = 0.006 * PACE; float WORD_CHANCE = 0.04; String[] WORDS = {"no", "stop", "don't", "betrayed", "forgotten", "alone", "empty", "cold", "trapped", "ashamed", "sorry", "afraid", "lost"}; String randomWord() { return WORDS[(int)random(WORDS.length)];} float stuff_clock; int ticks; int damage; int x = 0xDEADBEEF; PVector playerPos; float CEIL = 10; float FLOOR = 470; int COLOR_SPREAD = 96; float lastbg; boolean muted; boolean playing; boolean gameover; boolean titlescreen; PImage snapshot; PFont font; class WordThing extends Thing { String word; WordThing(color col, float rad, PVector p, PVector v) { super(col, rad, p, v); word = randomWord(); } void draw() { fill(c); textAlign(CENTER, CENTER); textFont(font, 64); text(word, pos.x, pos.y); } void perturb() { word = randomWord(); } } class Thing { ArrayList vertices; color c; float r; PVector pos; PVector vel; Thing(color col, float rad, PVector p, PVector v) { c= col; r = rad; pos = p; vel = v; vertices = new ArrayList(); int SIDES = 13; for(int i = 0; i < SIDES; i++) { vertices.add(new PVector(cos(TWO_PI / SIDES * i) * r, sin(TWO_PI / SIDES * i) * r)); } } void draw() { fill(c); noStroke(); // ellipse(pos.x, pos.y, r, r); beginShape(); for(int i = 0; i < vertices.size(); i++) vertex(pos.x + ((PVector)vertices.get(i)).x, pos.y + ((PVector)vertices.get(i)).y); endShape(CLOSE); } void perturb() { float amt = r / 30; for(int i = 0; i < vertices.size(); i++) { ((PVector)vertices.get(i)).x += random(amt*2) - amt; ((PVector)vertices.get(i)).y += random(amt*2) - amt; } } } void startGame() { damage = 0; ticks = 0; lastbg = 128; breaks = 0; if(!muted) out.unmute(); playerPos = new PVector(width/2, height * 0.8); stuff = new ArrayList(); stuff_clock = 0; playing = true; gameover = false; titlescreen = false; } void titleScreen() { damage = 0; playing = false; gameover = false; titlescreen = true; } void gameOver() { snapshot = createImage(width, height, RGB); snapshot.loadPixels(); loadPixels(); for(int i = 0; i < pixels.length; i++) snapshot.pixels[i] = pixels[i]; snapshot.updatePixels(); //snapshot.filter(BLUR); playing = false; gameover = true; out.mute(); } void setup() { size(480, 480, P2D); frameRate(60); ellipseMode(RADIUS); font = loadFont("Garamond-64.vlw"); minim = new Minim(this); out = minim.getLineOut(); pn = new PinkNoise(1.0); out.addSignal(pn); bpf = new BandPass(440, 200, out.sampleRate()); out.addEffect(bpf); out.mute(); titleScreen(); } void stop() { out.close(); minim.stop(); super.stop(); } void addThing() { float difficulty = SPEED_BASE + ticks * SPEED_RATE; color c = color(128 + COLOR_SPREAD*((int)random(3)-1)); float radius = SIZE_BASE + ticks * SIZE_RATE; PVector pos = new PVector(random(width), -radius); PVector vel = new PVector(random(difficulty) - difficulty/2, difficulty); if(random(1) < WORD_CHANCE) { pos.x = width/2; difficulty = SPEED_BASE; radius = SIZE_BASE; vel = new PVector(random(difficulty) - difficulty/2, difficulty); stuff.add(0, new WordThing(color(lastbg), radius, pos, vel)); } else stuff.add(0, new Thing(c, radius, pos, vel)); } void noiseShader() { int ratio = 256/MAXDAM; loadPixels(); for(int i = 0; i < pixels.length; i++) { x = ((x << 1) + (((x >> 27) ^ (x >> 30)) & 1)); if((x & 0xFF) <= red(pixels[i])) pixels[i] = color(255, 255-damage*ratio, 255-damage*ratio); else pixels[i] = color(0); } updatePixels(); } void controls() { float SPEED = 3; if(keys[UP]) playerPos.y -= SPEED; if(keys[DOWN]) playerPos.y += SPEED; if(keys[LEFT]) playerPos.x -= SPEED; if(keys[RIGHT]) playerPos.x += SPEED; if(playerPos.x < 0) playerPos.x = 0; if(playerPos.x >= width) playerPos.x = width - 1; if(playerPos.y < CEIL) playerPos.y = CEIL; if(playerPos.y > FLOOR) playerPos.y = FLOOR; } void draw() { if(titlescreen) { background(5); textFont(font, 64); textAlign(CENTER, CENTER); fill(128); text("squidfold", width/2, height/2); textFont(font, 32); text("[space]", width/2, height * 0.75); noiseShader(); } else if(gameover) { // snapshot.filter(BLUR); snapshot.loadPixels(); for(int melt = 0; melt < 1; melt++) for(int i = snapshot.pixels.length - 2; i > width; i--) { x = ((x << 1) + (((x >> 27) ^ (x >> 30)) & 1)); color c; int fuzz = (x&0xFF)%3 - 1; x = ((x << 1) + (((x >> 27) ^ (x >> 30)) & 1)); if(red(snapshot.pixels[i-fuzz]) < red(snapshot.pixels[i-width]) && x % 2 == 0) { c = snapshot.pixels[i-fuzz]; snapshot.pixels[i-fuzz] = snapshot.pixels[i - width]; snapshot.pixels[i - width] = c; } } snapshot.updatePixels(); background(0); image(snapshot, 0, 0); fill(255); textFont(font, 64); textAlign(CENTER, CENTER); text("end", width/2, height/2); textFont(font, 32); text("result: "+(ticks/6)+"\nbroken: "+breaks, width/2, height*0.8); loadPixels(); for(int i = 0; i < pixels.length; i++) { if(green(pixels[i]) > 16) { if(red(snapshot.pixels[i]) > 128) pixels[i] = color(0); else pixels[i] = color(255, 0, 0); } } updatePixels(); } else { controls(); float bg = 128;///map(playerPos.y, FLOOR, CEIL, 0, 254); if(keys['Z']) bg += COLOR_SPREAD; if(keys['X']) bg -= COLOR_SPREAD; bg = (bg+lastbg*10)/11; lastbg = bg; background(bg); ticks++; stuff_clock += BASE_RATE + ACCEL_FACTOR * ticks; if(stuff_clock > 1) { stuff_clock = 0; addThing(); } Iterator si = stuff.iterator(); while(si.hasNext()) { Thing t = (Thing) si.next(); t.pos.add(t.vel); if(t.pos.y > height + t.r) si.remove(); else { if(abs(red(t.c)-lastbg) < COLOR_SPREAD/2) t.perturb(); t.draw(); } } /* fill(128); ellipse(width/2, height/2, 100, 100); fill(5); ellipse(width/2 + 100, height/2, 100, 100); fill(250); ellipse(width/2 - 100, height/2, 100, 100); */ float passBand = map(bg, 0, 255, 300, 1800); passBand = max(passBand, 50); bpf.setFreq(passBand); bpf.setBandWidth(passBand * 0.2 * ((MAXDAM * 1.0 - damage) / MAXDAM) ); noStroke(); float spin = ticks / 5.0; fill(255); //////////////////////////////////////COLLISION DETECTION if(abs(red(get((int)playerPos.x, (int)playerPos.y))-bg) > COLOR_SPREAD/2) { damage++; if(damage > MAXDAM) { damage = MAXDAM; } } else { if(damage > BREAKDAM) { damage = 0; breaks++; background(255); bpf.setFreq(2000); bpf.setBandWidth(1900); } if(ticks % RECOVER == 0) damage--; if(damage < 0) damage = 0; } stroke(bg); strokeWeight(7); noFill(); rect(0, 0, width, height); noStroke(); fill(255); ellipse(playerPos.x, playerPos.y, 10, 10); fill(0); arc(playerPos.x, playerPos.y, 10, 10, spin, spin + HALF_PI); arc(playerPos.x, playerPos.y, 10, 10, spin + PI, spin + HALF_PI + PI); fill(255); ellipse(playerPos.x, playerPos.y, 5, 5); fill(0); arc(playerPos.x, playerPos.y, 5, 5, -spin, -spin + HALF_PI); arc(playerPos.x, playerPos.y, 5, 5, -spin + PI, -spin + HALF_PI + PI); if(!keys['1']) noiseShader(); //println(frameRate); if(damage == MAXDAM) gameOver(); fill(0, 255, 0); textAlign(LEFT, BOTTOM); textFont(font, 64); //text(""+frameRate, 0, height); } } 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 == 'Q') ticks+=1000; if(theKey == 'M') { muted = !muted; if(muted) out.mute(); else out.unmute(); } if((theKey == ' ') && gameover) { titleScreen(); } else if((theKey == ' ') && titlescreen) { startGame(); } } void up(int theKey) { //println(theKey + " up"); }