Last active
September 25, 2019 20:00
-
-
Save BenMaydan/cb939be2ce0281a844a7190cb1e29c45 to your computer and use it in GitHub Desktop.
Flappy bird with processing 3 and Java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class World { | |
public ArrayList<float[]> clouds = new ArrayList<float[]>(); | |
public void drawClouds() { for (float[] c : this.clouds) { fill(255); ellipse(c[0], c[1], c[2], c[3]); noFill(); } } | |
public void createCloud(float w, float h) { this.clouds.add(new float[] {random(this.clouds.get(this.clouds.size()-1)[0] + w, width), random(height/5), w, h}); } | |
public void createClouds(int times, float w, float h) { for (int ii = 0; ii < times; ii += 1) { this.clouds.add(new float[] {random(width), random(height/5), w, h}); } } | |
} | |
class Bird { | |
private int x, y, dy; | |
private int r, g, b; | |
private float rad, dia, eyeSize, pupilSize; | |
private boolean wait = true; | |
Bird(int x, int y, float rad, float eye, float pupil, int r, int g, int b) { this.x = x; this.y = y; this.r = r; this.g = g; this.b = b; this.rad = rad; this.dia = this.rad*2; this.eyeSize = eye; this.pupilSize = pupil; } | |
public void show() { | |
fill(this.r, this.g, this.b); | |
circle(this.x, this.y, this.dia); | |
// Calculate distance from center of circle to the upper right corner of the circle | |
float[] point_on_circle = pointOnCircle(this.x, this.y, this.rad, radians(315)); | |
float point_x = point_on_circle[0]; | |
float point_y = point_on_circle[1]; | |
//float dist = sqrt(pow(this.rad, 2) / 2); | |
fill(255); | |
circle(point_x, point_y, this.eyeSize); | |
fill(0); | |
circle(point_x, point_y, this.pupilSize); | |
noFill(); | |
} | |
public void flap(float amount) { this.y -= amount; } | |
public void fall(float amount) { | |
if (this.wait == false) { | |
if (this.y + this.rad < height) { this.y += amount; } | |
else { | |
println("YOU COLLIDED WITH THE FLOOR!"); | |
println("YOUR SCORE: " + round(score)); | |
game_over = true; | |
noLoop(); | |
} | |
} | |
else { this.wait = false; } | |
} | |
} | |
class Pipe { | |
private int x, w; | |
private int r, g, b; | |
private float y, h; | |
Pipe(int x, int w, int[] c) { this.x = x; this.w = w; this.r = c[0]; this.g = c[1]; this.b = c[2]; } | |
public void build(float y, float h) { | |
try { | |
// Assertions to confirm opening is not off of the screen and openings do not overlap each other | |
assert y < height && y > 0 : "The bottom of the opening of the pipe should not be off of the screen"; | |
assert y-h < height && y-h > 0 : "The top of the opening of the pipe should not be off of the screen"; | |
assert y > y-h : "The bottom of the opening of the pipe and the top of the opening of the pipe should not overlap"; | |
// Assertion to confirm opening is big enough for the bird | |
assert h > bird.dia : "The opening of the pipe should be big enough for the bird."; | |
this.y = y; | |
this.h = h; | |
} | |
catch (AssertionError e) { println(e); println("Bottom={" + y + "}\nTop={" + (y-h) + "}" + "\nHeight={" + height + "}"); exit(); } | |
} | |
public void show() { | |
fill(this.r, this.g, this.b); | |
rect(this.x, 0, this.w, this.y-this.h); | |
rect(this.x, this.y, this.w, height-this.y); | |
noFill(); | |
} | |
public void move(int amount) { this.x -= amount; } | |
} | |
float[] pointOnCircle(int x, int y, float rad, float radians) { | |
return new float[] {x+(rad * cos(radians)), y+(rad * sin(radians))}; | |
} | |
float[] random_opening(float smallest_height, float biggest_height) { | |
float[] b_h = new float[2]; | |
b_h[0] = random(biggest_height, height-10); | |
b_h[1] = random(smallest_height, biggest_height); | |
return b_h; | |
} | |
boolean circlePipeCollision(Bird b, float x, float y, float w, float h) { | |
float dx = abs(b.x - max(x, min(b.x, x + w))); | |
float dy = abs(b.y - max(y, min(b.y, y + h))); | |
return (dx * dx + dy * dy) < (b.rad * b.rad); | |
} | |
World world; | |
Bird bird; | |
ArrayList<Pipe> pipes = new ArrayList<Pipe>(); | |
boolean check_score = true; | |
float score = 0; | |
boolean game_over = false; | |
void setup() { | |
fullScreen(); | |
frameRate(120); | |
focused = true; | |
int x = width/10; int y = height/2; int rad = height/10; | |
int eye = 100; int pupil = 15; | |
// Setting up the game | |
world = new World(); | |
world.createClouds(5, 300, 100); | |
bird = new Bird(x, y, rad, eye, pupil, 255, 255, 0); | |
pipes.add(new Pipe(width, 100, new int[] {0, 255, 0})); | |
//float[] ro = random_opening(50+bird.dia, 100+bird.dia); | |
float[] ro = random_opening(200+bird.dia, 300+bird.dia); | |
pipes.get(0).build(ro[0], ro[1]); | |
} | |
void draw() { | |
if (game_over) { noLoop(); } | |
// Only update the game if the game currently has the focus | |
if (focused == true) { | |
background(0, 150, 255); | |
world.drawClouds(); | |
bird.show(); | |
float br = bird.rad; | |
for (Pipe p : pipes) { | |
int px = p.x; float py = p.y; float ph = p.h; int pw = p.w; | |
p.show(); | |
for (int ii = 0; ii <= 360; ii += 1) { | |
if (circlePipeCollision(bird, px, 0, pw, py-ph) || circlePipeCollision(bird, px, py, pw, height-py)) { | |
println("YOU COLLIDED WITH A PIPE!"); | |
println("YOUR SCORE: " + round(score)); | |
game_over = true; | |
break; | |
} | |
} | |
// Increment score if center of the bird is in a pipe | |
// Incrementing the score is kind of a hack. It increments by 0.1 because this statement is checked 10 times per pipe | |
if (check_score == true) { if (bird.x > px && bird.x < px + pw && bird.y > py - ph && bird.y < py) { score += 0.1; } } | |
// No collision, so move pipe and continue checking for collisions | |
p.move(5); | |
} | |
// No collision, so move bird and continue with the program | |
if (keyPressed == false) { bird.fall(8); } | |
// If the last pipe is in view, create a new pipe | |
if (pipes.get(pipes.size()-1).x + pipes.get(pipes.size()-1).w <= width) { | |
pipes.add(new Pipe(pipes.get(pipes.size()-1).x + 600, 100, new int[] {0, 255, 0})); | |
// Generate random y value of the size of the pipe's opening | |
float[] ro = random_opening(150+bird.dia, 150+bird.dia); | |
// The y value of the bottom of the pipe ranges from enough for the bird to enter to + 50 | |
pipes.get(pipes.size()-1).build(ro[0], ro[1]); | |
} | |
// Checks if the first pipe is off the screen and if it is it is deleted | |
if (pipes.size() >= 1 && pipes.get(0).x + pipes.get(0).w <= 0) { pipes.remove(0); } | |
} | |
} | |
void keyPressed() { | |
if (game_over == true && key == 89) { loop(); game_over = false; } | |
if (key == CODED && keyCode == UP) { bird.flap(100); focused = true; bird.wait = true; } | |
else { bird.wait = true; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment