Skip to content

Commit 23888b1

Browse files
committed
Flappy Bird
1 parent ee61e32 commit 23888b1

File tree

10 files changed

+1933
-0
lines changed

10 files changed

+1933
-0
lines changed

flappy-bird/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Famous hyper-casual mobile game Flappy Bird made with javascript canvas.
2+
3+
This project's intention is to practice on web development and this project lacks of some features.
4+
You as a starter may fork this repo and add missing features such as;
5+
- Play / Pause button
6+
- Use numbers on sprite image to show score
7+
- Add rotation behaviour to bird
8+
and more...
9+
10+
Speed code video and result:
11+
https://youtu.be/Wk9EhC-BfKc

flappy-bird/game.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import vars from "./modules/vars.js";
2+
import Bird from "./modules/bird.js";
3+
import Ground from "./modules/ground.js";
4+
import Column from "./modules/column.js";
5+
6+
7+
let frame = 0; // frame number in current second
8+
let score = 0;
9+
10+
const canvasElement = document.getElementById("c");
11+
const context = canvasElement.getContext("2d");
12+
13+
const canvasHeight = Math.floor(window.innerHeight);
14+
const canvasWidth = Math.floor(canvasHeight * 9/16);
15+
canvasElement.width = canvasWidth;
16+
canvasElement.height = canvasHeight;
17+
18+
// calculate gravity
19+
// in 5 seconds gravity must pull bird top to bottom
20+
vars.GRAVITY = Math.floor(canvasHeight / (-1 * 5 * vars.FPS));
21+
22+
// sprite
23+
const sprite = new Image();
24+
sprite.src = "sprite.png";
25+
26+
// game elements
27+
const bird = new Bird(context, sprite);
28+
const ground = new Ground(context, sprite);
29+
const columns = new Column(context, sprite);
30+
31+
// bind event on column revive to inscrease score
32+
columns.onRevive = increaseScore;
33+
34+
canvasElement.onclick = () => {
35+
bird.jump();
36+
}
37+
38+
const gameInterval = setInterval(() => {
39+
// clear canvas
40+
context.clearRect(0, 0, canvasWidth,canvasHeight);
41+
42+
// draw bird
43+
bird.draw(frame);
44+
45+
// draw ground
46+
ground.draw(frame);
47+
48+
// draw columns
49+
columns.draw(frame);
50+
51+
52+
// check if bird touched ground
53+
if(bird.isTouchingGround(ground)) {
54+
alert("Game Over");
55+
clearInterval(gameInterval);
56+
}
57+
58+
// check if bird touched columns
59+
if(bird.isTouchingColumns(columns)) {
60+
alert("Game Over");
61+
clearInterval(gameInterval);
62+
}
63+
64+
// print score
65+
context.fillStyle = "black";
66+
context.textAlign = "center";
67+
context.font = "38px Arial";
68+
context.fillText(score, canvasWidth/2, 40);
69+
70+
frame = (frame + 1) % vars.FPS;
71+
72+
}, 1000 / vars.FPS);
73+
74+
function increaseScore() {
75+
score += 1;
76+
}

flappy-bird/index.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Flappy Bird</title>
7+
<style>
8+
html, body {
9+
margin: 0;
10+
padding: 0;
11+
}
12+
#c {
13+
display: flex;
14+
margin: auto;
15+
background-image: url(sprite.png);
16+
background-position: 0 0;
17+
background-size: 355%; /* proportion of sprite image to background */
18+
}
19+
</style>
20+
</head>
21+
<body>
22+
<canvas id="c"></canvas>
23+
<script src="game.js" type="module"></script>
24+
</body>
25+
</html>

flappy-bird/modules/bird.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import vars from "./vars.js";
2+
3+
export default class Bird {
4+
constructor(context, sprite) {
5+
this.context = context;
6+
this.sprite = sprite;
7+
8+
// initial position of bird
9+
this.position = {
10+
x: 0, y: 0
11+
}
12+
13+
// positions of bird on sprite image
14+
this.frames = [
15+
{x: 3, y: 491},
16+
{x: 31, y: 491},
17+
{x: 59, y: 491}
18+
];
19+
20+
// bird's dimensions on canvas according to background image
21+
this.width = 17 * this.context.canvas.width / 144;
22+
this.height = 12 * this.context.canvas.height / 256;
23+
}
24+
25+
draw(frame) {
26+
// regulate frame. sprite seems 9 FPS
27+
frame = Math.floor(frame * 9 / vars.FPS);
28+
29+
// add gravity
30+
this.position.y = Math.max(0, this.position.y - vars.GRAVITY);
31+
32+
this.context.drawImage(
33+
this.sprite,
34+
this.frames[frame%this.frames.length].x,
35+
this.frames[frame%this.frames.length].y,
36+
17, 12, // bird's dimension on sprite image
37+
this.position.x, this.position.y, // bird's position on canvas
38+
this.width, this.height // bird's dimension on canvas
39+
)
40+
}
41+
42+
jump() {
43+
this.position.y += vars.GRAVITY * vars.FPS * .6;
44+
}
45+
46+
isTouchingGround(ground) {
47+
return (this.position.y + this.height) > (this.context.canvas.height - ground.height);
48+
}
49+
50+
isTouchingColumns(columns) {
51+
if( (this.position.x + this.width) > columns.position.x ) {
52+
if(
53+
this.position.y < columns.gapTopPosition ||
54+
this.position.y > (columns.gapTopPosition + columns.gap)
55+
) {
56+
return true;
57+
}
58+
}
59+
60+
return false;
61+
}
62+
}

flappy-bird/modules/column.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import vars from "./vars.js";
2+
3+
export default class Column {
4+
constructor(context, sprite) {
5+
this.context = context;
6+
this.sprite = sprite;
7+
8+
// this is the gap between top and bottom column
9+
// 1/4 of the canvas height
10+
this.gap = this.context.canvas.height * .25;
11+
this.gapTopPosition = this.context.canvas.height * .3;
12+
13+
this.height = 160 * this.context.canvas.height / 256;
14+
this.width = 26 * this.context.canvas.width / 144;
15+
16+
this.position = {
17+
x: this.context.canvas.width, // start right side of canvas
18+
topY: this.gapTopPosition - this.height, // top column y position
19+
bottomY: this.gapTopPosition + this.gap // bottom column y position
20+
}
21+
22+
}
23+
24+
draw(frame) {
25+
// check if out of canvas
26+
if(this.position.x + this.width < 0) {
27+
this.reviveColumn();
28+
}
29+
30+
// regulate frame - optional
31+
frame = Math.floor(frame * 9 / vars.FPS);
32+
33+
// in 3 seconds pass whole canvas
34+
this.position.x -= this.context.canvas.width / (3 * vars.FPS);
35+
36+
// draw top
37+
this.context.drawImage(
38+
this.sprite,
39+
56, 323,
40+
26, 160,
41+
this.position.x, this.position.topY,
42+
this.width, this.height
43+
);
44+
45+
// draw bottom
46+
this.context.drawImage(
47+
this.sprite,
48+
84, 323,
49+
26, 160,
50+
this.position.x, this.position.bottomY,
51+
this.width, this.height
52+
);
53+
}
54+
55+
reviveColumn() {
56+
this.position.x = this.context.canvas.width;
57+
58+
// generate a random number between .1 - .5
59+
let randNum = Math.floor(Math.random() * 50) / 100;
60+
randNum = randNum < .1 ? .1 : randNum;
61+
62+
this.gapTopPosition = this.context.canvas.height * randNum;
63+
this.position.topY = this.gapTopPosition - this.height;
64+
this.position.bottomY = this.gapTopPosition + this.gap;
65+
66+
this.onRevive();
67+
}
68+
}

flappy-bird/modules/ground.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import vars from "./vars.js";
2+
3+
export default class Ground {
4+
constructor(context, sprite) {
5+
this.context = context;
6+
this.sprite = sprite;
7+
8+
this.height = 56 * this.context.canvas.height / 256;
9+
this.width = 168 * this.context.canvas.width / 144;
10+
11+
this.position = {
12+
x: 0,
13+
y: this.context.canvas.height - this.height
14+
}
15+
16+
// ground image has 12px pattern loop
17+
// move 2px on every frame than turn back
18+
this.frames = [
19+
{x: 292, y:0},
20+
{x: 294, y:0},
21+
{x: 296, y:0},
22+
{x: 298, y:0},
23+
{x: 300, y:0},
24+
{x: 302, y:0},
25+
{x: 304, y:0},
26+
]
27+
}
28+
29+
draw(frame) {
30+
// regulate frame
31+
frame = Math.floor(frame * this.frames.length / vars.FPS);
32+
33+
this.context.drawImage(
34+
this.sprite,
35+
this.frames[frame%this.frames.length].x,
36+
this.frames[frame%this.frames.length].y,
37+
168, 56,
38+
this.position.x, this.position.y,
39+
this.width, this.height
40+
)
41+
}
42+
}

flappy-bird/modules/vars.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default {
2+
GRAVITY: -5, // default value, will depend on canvas height - px per frame
3+
FPS: 16
4+
}

0 commit comments

Comments
 (0)