import ddf.minim.*; /** * Game 21: "Much Worse"
* A/D or arrows to move left/right
* Click to throw grenade
*
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; int ISLAND_TOP = 320; int ISLAND_SIDES = 0; float ISLAND_DOME = 0.0018; int LAVA_LEVEL = 20; int GRENADE_LIFE = PHYSICS_FPS*2/3; float GRENADE_GRAVITY = 0.03; float GRENADE_LAUNCH_KICK = GRENADE_LIFE * GRENADE_GRAVITY / 2; int MAX_GRENADES = 2; int EXPLOSION_LIFE = 60; int GRENADE_EXPLO_RADIUS = 30; int METEOR_TIME = 20 * PHYSICS_FPS; int START_METEORS_PER_TIME = 7; float METEOR_SPEED = 5; int METEOR_WARN = GRENADE_LIFE * 3; int METEOR_SPAWN_AHEAD = PHYSICS_FPS*3; float METEOR_BLAST_RADIUS = 50; int METEOR_HIT_SCORE = 50; int METEOR_SURVIVE_SCORE = 10; int physics_frame; ArrayList grenades; ArrayList meteors; ArrayList explosions; ParticleList particles; PVector player_pos; int[][] ground; int meteor_timer; int meteors_per_time; int score; int topscore; boolean gameover; String gameover_text; PFont font; AudioSample grenadeToss; AudioSample grenadeBoom; AudioSample meteorBoom; AudioSample meteorWarn; AudioSample meteorFall; void setup() { size(720, 480); frameRate(600); font = loadFont("PressStartK-16.vlw"); audioInit(); newGame(); gameover = true; gameover_text = "MUCH WORSE"; } void audioInit() { minim = new Minim(this); grenadeToss = minim.loadSample("grenade_toss.wav", 1024); grenadeBoom = minim.loadSample("grenade_hit.wav", 1024); meteorBoom = minim.loadSample("meteor_hit.wav", 1024); meteorWarn = minim.loadSample("meteor_warn.wav", 1024); meteorFall = minim.loadSample("meteor_fall.wav", 1024); } void audioClose() { grenadeToss.close(); grenadeBoom.close(); meteorBoom.close(); meteorWarn.close(); meteorFall.close(); minim.stop(); } boolean worldIsSolid(int x, int y) { if(x < 0 || x >= width) return false; if(y < 0 || y >= height) return false; return ground[x][y] != 0; } void newGame() { ground = new int[width][height]; for(int x = 0; x < width; x++) for(int y = 0; y < height; y++) { if(y > (ISLAND_TOP + (x-width/2)*(x-width/2)*ISLAND_DOME) && x >= ISLAND_SIDES && x < width-ISLAND_SIDES) ground[x][y] = 1; } grenades = new ArrayList(); meteors = new ArrayList(); explosions = new ArrayList(); particles = new ParticleList(); player_pos = new PVector(width/2, ISLAND_TOP-1); meteor_timer = 0; physics_frame = 0; meteors_per_time = START_METEORS_PER_TIME; score = 0; gameover = false; } void stop() { audioClose(); super.stop(); } void physicsStep() { physics_frame++; particles.tick(); if(!gameover) { meteor_timer ++; if(meteor_timer % (METEOR_TIME / meteors_per_time + 1) == 0) meteors.add(new Meteor()); if(meteor_timer >= METEOR_TIME) { meteor_timer = 0; meteors_per_time ++; } } Iterator gi = grenades.iterator(); while(gi.hasNext()) { Grenade g = (Grenade) gi.next(); g.tick(); if(worldIsSolid((int)g.pos.x, (int)g.pos.y)) g.life = 0; if(g.life <= 0) { //TODO blow up if(!muted) grenadeBoom.trigger(); explosions.add(new Explosion(g.pos, GRENADE_EXPLO_RADIUS)); gi.remove(); } } Iterator ei = explosions.iterator(); while(ei.hasNext()) { Explosion e = (Explosion) ei.next(); if(e.life == EXPLOSION_LIFE) { e.eatDirt(); } e.tick(); if(e.life <= 0) { ei.remove(); } } Iterator mi = meteors.iterator(); while(mi.hasNext()) { boolean blewup = false; Meteor m = (Meteor) mi.next(); m.tick(); if(worldIsSolid((int)m.pos.x, (int)m.pos.y) || m.pos.y >= height) { //TODO blow up if(!gameover) score += METEOR_SURVIVE_SCORE; blewup = true; mi.remove(); } else { ei = explosions.iterator(); while(ei.hasNext()) { Explosion e = (Explosion) ei.next(); if(inRadius(e.pos, m.pos, e.radius)) { //TODO blow up blewup = true; mi.remove(); if(!gameover) score+= METEOR_HIT_SCORE; break; } } } if(blewup) { explosions.add(new Explosion(m.pos, METEOR_BLAST_RADIUS)); if(!muted) meteorBoom.trigger(); } } // boolean bias = false; //if(random(2) > 1) bias = true; for(int x = 1; x < width - 1; x++) for(int y = height-2; y >= 0; y--) { if(ground[x][y] != 0) { // bias = !bias; if(ground[x][y+1] == 0) {ground[x][y] = 0; ground[x][y+1] = 2;} else if(ground[x][y] == 2) { if(ground[x+1][y+1] == 0) {ground[x][y] = 0; ground[x+1][y+1] = 2;}// bias = !bias;} else if(ground[x-1][y+1] == 0) {ground[x][y] = 0; ground[x-1][y+1] = 2;}// bias = !bias;} } } } if(!gameover) { if(!worldIsSolid((int)player_pos.x, (int)player_pos.y+1)) player_pos.y++; if(worldIsSolid((int)player_pos.x, (int)player_pos.y)) player_pos.y--; if(keys[LEFT] || keys['A']) if(!worldIsSolid((int)player_pos.x-1, (int)player_pos.y-2)) player_pos.x--; if(keys[RIGHT] || keys['D']) if(!worldIsSolid((int)player_pos.x+1, (int)player_pos.y-2)) player_pos.x++; if(player_pos.y > height - LAVA_LEVEL) { gameover = true; gameover_text = "GAME OVER:\nfell in lava"; } } } void drawingStep() { ellipseMode(RADIUS); background(64, 0, 32); particles.draw(); // stroke(160, 160, 160); loadPixels(); for(int x = 0; x < width; x++) for(int y = 0; y < height; y++) { if(ground[x][y]==1) pixels[x+y*width] = color(190, 160, 130); if(ground[x][y]==2) pixels[x+y*width] = color(160, 130, 100); } updatePixels(); noStroke(); fill(255, 150, 0); rect(0, height-LAVA_LEVEL, width, LAVA_LEVEL); fill(96, 255, 255); if(!gameover) rect(player_pos.x - 2, player_pos.y - 2, 5, 5); fill(0, 192, 32); Iterator gi = grenades.iterator(); while(gi.hasNext()) { Grenade g = (Grenade) gi.next(); rect(g.pos.x - 1, g.pos.y - 1, 3, 3); } Iterator mi = meteors.iterator(); while(mi.hasNext()) { Meteor m = (Meteor) mi.next(); m.draw(); } Iterator ei = explosions.iterator(); while(ei.hasNext()) { Explosion e = (Explosion) ei.next(); e.draw(); } textFont(font); fill(255); textAlign(LEFT, TOP); topscore = max(topscore, score); text("Score: "+score+"\nTop: "+topscore, 8, 8); if(gameover) { textAlign(CENTER, CENTER); text(gameover_text+"\n\nclick to start", width/2, height/2); } } 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(grenades.size() < MAX_GRENADES && !gameover) { grenades.add(new Grenade()); if(!muted) grenadeToss.trigger(); } if(gameover && meteors.isEmpty() && grenades.isEmpty()) { 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' && !title) paused = !paused; } void up(int theKey) { println(theKey + " up"); }