/**
Game 01: "No Rain Today"
Use left and right arrows to turn
Press space to flap upward
Press P to pause
Don't let it rain

This work by Nathan McCoy is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
*/
//
ArrayList downKeys;
float px, py, dx, dy;
PFont font;
int SPACE = 32;
float OMEGA = 0.1;
//float DRAG = 0.997;
float DRAGCOEFF = 1.0/3000;
float ROTDRAG = 1;
float FLAP = 3;
float STALLSPEED = 0;
float PLAYER_RADIUS = 16;
boolean paused = false;
boolean gameover = true;
ParticleSet particles;
ParticleSet steampuffs;
ParticleSet rainsplashes;
ArrayList clouds;
ArrayList rain;
float RAINSPEED = 2.0;
float RAINDAMAGE = 0.01;
float INTENSITY_RATE = 1.0/3000;
float CLOUDCOUNT = 100;
float CLOUDMAX = 50;
float CLOUDGROWTH = 0.02;
float CLOUD_INTENSITY = 1.0/5000;
float time = 0;
float life = 1.0;
int score = 0;
int combo;
float combofade;
PVector combopos;
boolean firstplay = true;
class Cloud extends PVector
{
float radius = CLOUDMAX;
Cloud(float x, float y)
{
super(x, y);
}
}
class Particle
{
float x, y, dx, dy;
int life;
int maxlife;
Particle(float px, float py, float vx, float vy, int lifespan)
{
x = px;
y = py;
dx = vx;
dy = vy;
life = lifespan;
maxlife = lifespan;
}
void update()
{
x += dx;
y += dy;
life--;
}
float age()
{
return float(life)/maxlife;
}
}
class ParticleSet extends ArrayList
{
void update()
{
Iterator i = iterator();
while(i.hasNext())
{
Object o = i.next();
if(o instanceof Particle)
{
Particle p = (Particle) o;
p.update();
if(p.life <= 0) i.remove();
}
}
}
}
void reset()
{
rain = new ArrayList();
particles = new ParticleSet();
steampuffs = new ParticleSet();
rainsplashes = new ParticleSet();
combo = 0;
combofade = 0;
combopos = new PVector(0, 0);
clouds = new ArrayList();
for(int i=0; i < CLOUDCOUNT; i++)
{
clouds.add(new Cloud(random(width), random(height/4)));
}
smooth();
noStroke();
fill(255, 153);
px = width/2;
py = height/2;
dx = 0;
dy = 0;
time = 0;
life = 1.0;
score = 0;
}
void setup()
{
font = loadFont("ARBERKLEY-48.vlw");
textFont(font, 32);
size(640, 480);
background(color(32+(1-life)*96, 128+40*life, 128+127*life));
frameRate(60);
downKeys = new ArrayList();
reset();
}
void rotateVel(float theta)
{
float newdx = cos(theta)*dx - sin(theta)*dy;
float newdy = sin(theta)*dx + cos(theta)*dy;
dx = newdx;
dy = newdy;
}
void draw()
{
if(paused)
{
textAlign(LEFT, TOP);
fill(#000000);
text("paused", 8, 8);
}
else if(gameover)
{
textAlign(LEFT, TOP);
fill(#000000);
if(firstplay)
{
text("No Rain Today\n\npress P to play", 8, 8);
fill(#FFFFFF);
text("No Rain Today\n\npress P to play", 6, 6);
}
else
{
text("No Rain Today\nscore: "+ Integer.toString(score) +"\npress P to play", 8, 8);
fill(#FFFFFF);
text("No Rain Today\nscore: "+ Integer.toString(score) +"\npress P to play", 6, 6);
}
}
else
{
time+= 1.0/frameRate;
//add raindrops from clouds
if(random(1) < time * INTENSITY_RATE)
{
PVector potentialDrop = new PVector(random(width), random(height/4));
for(int i = 0; i < clouds.size(); i++)
{
Cloud c = (Cloud)clouds.get(i);
if(c.dist(potentialDrop) CLOUDMAX/2)
{
rain.add(potentialDrop); break;
}
}
}
float speed = sqrt(dx*dx + dy*dy);
float turnpower = min(speed / STALLSPEED, 1);
background(color(32+(1-life)*96, 128+40*life, 128+127*life));
float rot = 0;
if(downKeys.contains(LEFT)) rot += -OMEGA * turnpower;
if(downKeys.contains(RIGHT)) rot += OMEGA * turnpower;
if(rot != 0)
{
rotateVel(rot);
dx *= ROTDRAG;
dy *= ROTDRAG;
}
//dx *= DRAG;
//dy *= DRAG;
float airdrag = speed * speed * DRAGCOEFF;
if(speed != 0)
{
dx -= (dx/speed) * airdrag;
dy -= (dy/speed) * airdrag;
}
dy += 0.1;
px += dx;
py += dy;
if(px < 0)
{
dx *= -0.5;
px = 0;
}
if(px > width)
{
dx *= -0.5;
px = width;
}
if(py > height) {
dy *= -0.5;
py = height;
}
//fill(255, 153);
//ellipse(px - dx*8/speed, py - dy*8/speed, 24, 24);
//ellipse(px + dx*8/speed, py + dy*8/speed, 24, 24);
//ellipse(px - dx, py - dy, 32, 32);
//do rain stuff
Iterator it = rain.iterator();
while(it.hasNext())
{
Object o = it.next();
PVector p = (PVector) o;
p.y += RAINSPEED;
if(p.y > height)
{
it.remove();
life -= RAINDAMAGE;
if(combo > 0)
{
combo = 0;
combopos = new PVector(p.x, p.y-40);
combofade = 1;
}
if(life <= 0) gameover = true;
rainsplashes.add(new Particle(p.x, p.y, 0, 0, 30));
}
else
{
float flicker = sin(p.x / 300 + p.y / 200 - time*10)*128+128;
fill(color(flicker, flicker, 255));
ellipse(p.x, p.y, 3, 10);
for(int i = 0; i CLOUDMAX) c.radius = CLOUDMAX;
float distance = c.dist(new PVector(px, py));
if(distance < c.radius + PLAYER_RADIUS)
c.radius = distance - PLAYER_RADIUS;
fill(200+55*life, 200+55*life, 200+55*life, 255*((c.radius/CLOUDMAX)*10-4));
ellipse(c.x, c.y, c.radius*2, c.radius*2);
}
//draw combo counter
fill(255, 255, 192, combofade*255);
textAlign(CENTER, CENTER);
text("x"+Integer.toString(combo), combopos.x, combopos.y);
combofade *= 0.97;
}
}
void down(int theKey)
{
println(theKey + " down");
if(theKey == 32 && !paused) dy -= FLAP;
}
void up(int theKey)
{
println(theKey + " up");
}
void keyPressed()
{
if(key == 'p')
{
if(!gameover) paused = !paused;
else{
reset();
firstplay = false;
gameover = false;
}
}
if(!downKeys.contains(keyCode))
{
downKeys.add(keyCode);
down(keyCode);
}
}
void keyReleased()
{
if(downKeys.indexOf(keyCode)!= -1)
{
downKeys.remove(downKeys.indexOf(keyCode));
up(keyCode);
}
}