import ddf.minim.*;
/**
* Game 15: "Grapplish"
* Hold spacebar to lock orbit
* Use left and right arrows to swing
* Ascend as far as possible within the time limit
*
Go play more games at NMcCoy.net!
* 
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 gameover;
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;
ArrayList nodes;
PVector player_pos;
PVector player_prevpos;
float GRAVITY = 0.010;
float SWING_STRENGTH = 0.005;
PVector active_node;
PVector best_node;
float radius;
float MIN_RADIUS = 14;
float camera_offset;
PFont font;
boolean scored;
float camera_creep;
float CAMERA_CREEP_ACCEL = 0.00001;
int MAX_TIME = 180*90;
int time;
int NUM_DOTS = 15;
void setup()
{
size(720, 480);
frameRate(600);
minim = new Minim(this);
font = loadFont("PressStartK-32.vlw");
title = true;
reset();
}
void reset()
{
nodes = new ArrayList();
player_pos = new PVector(width/2, height/2);
player_prevpos = new PVector(width/2, height/2);
for(int i = 0; i < NUM_DOTS; i++) nodes.add(new PVector(random(width), -height + i*(height*2)/NUM_DOTS));
camera_creep = 0;
camera_offset = 0;
gameover = false;
time = MAX_TIME;
title = paused = true;
active_node = null;
best_node = null;
//else paused = false;
}
void stop()
{
minim.stop();
super.stop();
}
void physicsStep()
{
//camera_creep += CAMERA_CREEP_ACCEL;
//camera_offset -= camera_creep;
PVector temp = new PVector(player_pos.x, player_pos.y);
if(player_pos.y < camera_offset + height*3)
{
player_pos.x += (player_pos.x - player_prevpos.x);
player_pos.y += (player_pos.y - player_prevpos.y) + GRAVITY;
if(keys[RIGHT]) player_pos.x += SWING_STRENGTH;
if(keys[LEFT]) player_pos.x -= SWING_STRENGTH;
}
else gameover = true;
time--;
if(time <=0 || gameover)
{
time = 0;
gameover = true;
active_node = null;
paused = false;
}
Iterator ni = nodes.iterator();
best_node = null;
float bestd = MAX_FLOAT;
while(ni.hasNext())
{
PVector n = (PVector) ni.next();
float f = PVector.dist(n, player_pos);
if(f < bestd && n.y < player_pos.y
//&& (!(keys[LEFT] && n.x > player_pos.x) && !(keys[RIGHT] && n.x < player_pos.x))
)
{
bestd = f;
best_node = n;
}
}
if(active_node != null)
{
float d = PVector.dist(active_node, player_pos);
// radius = max(min(radius - 0.0, d), MIN_RADIUS);
//if(keys[DOWN]) radius += 0.3;
//if(d > radius)
{
PVector to_player = PVector.sub(player_pos, active_node);
to_player.normalize();
to_player.mult(radius);
player_pos = PVector.add(active_node, to_player);
}
}
player_prevpos = temp;
scored = false;
if(player_pos.y < camera_offset + height/2)
{
camera_offset = player_pos.y - height/2;
scored = true;
}
ni = nodes.iterator();
while(ni.hasNext())
{
PVector n = (PVector) ni.next();
if(n.y > camera_offset + height && n != active_node)
{
n.x = random(width);
n.y = n.y - height*2;//camera_offset - height + random(height);
}
}
}
void drawingStep()
{
background(0);
ellipseMode(RADIUS);
pushMatrix();
translate(0, -camera_offset);
// if(active_node != null)
// {
// stroke(255);
// line(player_pos.x, player_pos.y, active_node.x, active_node.y);
// }
noStroke();
fill(192);
float bestd = MAX_FLOAT;
PVector closest = player_pos;
strokeWeight(2);
Iterator ni = nodes.iterator();
while(ni.hasNext())
{
PVector n = (PVector) ni.next();
float d = PVector.dist(n, player_pos);
stroke(30000/(d+50), 0, 30000/(d+100));
noFill();
ellipse(n.x, n.y, d, d);
fill(30000/(d+50), 0, 30000/(d+100));
noStroke();
float timerat = time / (float)MAX_TIME;
ellipse(n.x, n.y, 7*timerat+0.5, 7*timerat+0.5);
}
// ni = nodes.iterator();
// while(ni.hasNext())
// {
// PVector n = (PVector) ni.next();
// noStroke();
// fill(192);
// ellipse(n.x, n.y, 7, 7);
//
// }
fill(64, 192, 192);
//ellipse(player_pos.x, player_pos.y, 7, 7);
noFill();
stroke(0, 255, 255);
if(best_node != null)
{
stroke(255, 192, 0);
float d = PVector.dist(best_node, player_pos);
ellipse(best_node.x, best_node.y, d, d);
}
if(active_node != null)
{
stroke(255, 255, 192);
float d = PVector.dist(active_node, player_pos);
ellipse(active_node.x, active_node.y, d, d);
}
popMatrix();
noStroke();
fill(255, 192, 0);
if(scored || gameover) fill(255, 255, 192);
textFont(font, 8);
textAlign(LEFT, TOP);
text("Score: "+(int)-camera_offset, 8, 16);
fill(255, 192, 0);
if(time < MAX_TIME/8 && (time/20)%2 == 0) fill(255, 255, 192);
rect(8, 6, (width-16)*time/MAX_TIME, 2);
fill(255, 192, 0);
if(gameover)
text("Press SPACE to play again.", 8, 4);
textAlign(CENTER, CENTER);
if(title) text("( Grapplish )\npress SPACE to start", width/2, height/2);
else if(paused) text("Paused", width/2, height/2);
}
void draw()
{
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 == 'P' && !gameover && !title)
{
paused = !paused;
}
if(theKey == ' ' && !gameover)
{
if(title)
{
title = false;
paused = false;
}
if(!paused)
{
if(player_pos.y < camera_offset + height) active_node = best_node;
if(active_node != null) radius = PVector.dist(active_node, player_pos);
}
// radius = MAX_FLOAT;
// Iterator ni = nodes.iterator();
// while(ni.hasNext())
// {
// PVector n = (PVector) ni.next();
// float f = PVector.dist(n, player_pos);
// if(f < radius)
// {
// radius = f;
// active_node = n;
// }
// }
}
if(theKey == ' ' && gameover && player_pos.y > camera_offset+height) reset();
}
void up(int theKey)
{
if(!paused)
{
if(!keys[' ']) active_node = null;
}
println(theKey + " up");
}