Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ body * {
flex-direction: column;
height: 100%;
}

canvas {
border: black 2px solid;
}
6 changes: 6 additions & 0 deletions assets/js/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
window.addEventListener('load', () => {
// iteration - 1: create & start the game
const game = new Game("canvas-game")

game.start()

// iteration - 2: add key listeners to the game
document.addEventListener('keydown', (e) => game.onKeyEvent(e));
document.addEventListener('keyup', (e) => game.onKeyEvent(e));
});
62 changes: 62 additions & 0 deletions assets/js/models/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
class Background {

constructor(ctx) {
this.ctx = ctx;
// positions
this.x = 0;
this.y = 434;
this.vx = 3;
this.width = this.ctx.canvas.width;
this.height = this.ctx.canvas.height;

this.bgImg = new Image();
this.bgImg.src = 'assets/img/game-bg.png';
// set image dimensions
this.bgImg.width = this.width;
this.bgImg.height = this.height;


this.footerImg = new Image();
this.footerImg.src = 'assets/img/game-bg-footer.png';
// set image dimensions
this.footerImg.width = this.width;
this.footerImg.height = 64;

}

draw() {
// iteration 1: draw the static backgorund img
this.ctx.drawImage(this.bgImg,
0,
0,
this.ctx.canvas.width,
this.ctx.canvas.height,
)

// iteration 1: draw footer img twice
this.ctx.drawImage(this.footerImg,
this.x,
this.y,
this.footerImg.width,
this.footerImg.height
);

this.ctx.drawImage(this.footerImg,
this.x + this.footerImg.width,
this.y,
this.footerImg.width,
this.footerImg.height
);
}

move() {
// iteration 1: move the ground
this.x -= this.vx;

// iteration 1: check bounds and reset position
if(this.x + this.footerImg.width < 0) {
this.x = 0;
}

}
}
40 changes: 37 additions & 3 deletions assets/js/models/flappybird.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class FlappyBird {
this.ctx = ctx;
this.x = x;
this.y = y;
this.jumpImpulse = 70;
this.jumpImpulse = 10;
this.vy = 3;

this.sprite = new Image();
Expand All @@ -22,32 +22,66 @@ class FlappyBird {
}

this.drawCount = 0;
this.wasJumping = false;
}

onKeyEvent(event) {
const isJumping = event.type === 'keydown';

switch (event.keyCode) {
case KEY_UP:
// iteration 2: jump! if necessary =D
if(isJumping && !this.wasJumping) {
this.vy = -this.jumpImpulse;
this.wasJumping = true
setTimeout(() => {
this.vy = 3;
}, 100);
} else if (!isJumping) this.wasJumping = false;
}
}

draw() {
// draw sprite

this.ctx.drawImage(this.sprite,
this.sprite.horizontalFrameIndex * this.width,
this.sprite.verticalFrameIndex * this.height,
this.width,
this.height,
this.x,
this.y,
this.width,
this.height
)
// animate sprite
this.animate();
}

animate() {
// iteration 2: configure frame animation

this.drawCount ++;

if(this.drawCount > 10) {
this.drawCount = 0;
this.sprite.horizontalFrameIndex ++;

if (this.sprite.horizontalFrameIndex >= this.sprite.horizontalFrames) {
this.sprite.horizontalFrameIndex = 0;
}
}
}

move() {
// iteration 2: move the y
this.y += this.vy;

}

collides(element) {
// iteration 3: check collisions (true|false)
return this.x < element.x + element.width &&
this.x + this.width > element.x &&
this.y < element.y + element.height &&
this.y + this.height > element.y;
}
}
59 changes: 56 additions & 3 deletions assets/js/models/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ class Game {
this.fps = 1000 / 60;

// iteration 1: setup the background
this.background = new Background(this.ctx);

// iteration 2: setup the flappy
this.bird = new FlappyBird(this.ctx,
0,
this.canvas.height/2);

this.pipes = [];
this.drawPipesCount = 0;
Expand All @@ -23,18 +27,32 @@ class Game {

onKeyEvent(event) {
// iteration 2: link flappy key events
this.bird.onKeyEvent(event);
}

start() {
if (!this.drawIntervalId) {
this.drawIntervalId = setInterval(() => {
// Iteration 1: each 60f clear - move - draw - [next iterations: addPipes - checkCollisions - checkScore]
this.clear();

this.move();

this.draw();

this.addPipes();

if(this.checkCollisions()) {
this.end();
}

}, this.fps);
}
}

stop() {
// Iteration 1: stop the game
clearInterval(this.drawIntervalId);
}

restart() {
Expand All @@ -43,33 +61,63 @@ class Game {

end() {
// Iteration 4: stop the game and setup score
this.stop();
}

clear() {
// Iteration 1: clean the screen
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}

move() {
// Iteration 1: move the background
this.background.move();
// Iteration 2: move the flappy
this.bird.move();
// Iteration 3: move the pipes
this.pipes.forEach(p => p.move());
}

addPipes() {
// Iteration 3: each draw pipes frequency cycles concat a pair of pipes to the pipes array and reset the draw cycle

if(this.drawPipesCount > this.pipesFrequency) {
this.drawPipesCount = 0;

const newPipes = this.randPairOfPipes();
this.pipes.push(newPipes[0]);
this.pipes.push(newPipes[1]);
}
}

randPairOfPipes() {
const space = this.canvas.height - this.background.footerImg.height;
const gap = (this.flappybird.height * 2) + this.flappybird.jumpImpulse;
const gap = (this.bird.height * 2) + this.bird.jumpImpulse*7;
const topSize = Math.floor(Math.random() * (space - gap) * 0.75)
const bottomSize = space - topSize - gap;
// Iteration 3: return two new pipes one at the top and other at the bottom
return []

return [
new Pipe(this.ctx, this.canvas.width, 0, topSize, "top"),
new Pipe(this.ctx, this.canvas.width, space - bottomSize, bottomSize, "bottom")
];
}

checkCollisions() {
// Iteration 4: check pipes collisions among flappy and end game if any pipe collides with the bird

if(this.bird.y < 0 || this.bird.y + this.bird.height > 434) {
return true;
}

if(this.pipes.find((p) => this.bird.collides(p))) {

return true;
}



return false;
}

checkScore() {
Expand All @@ -78,8 +126,13 @@ class Game {

draw() {
// Iteration 1: draw the background
this.background.draw();
// Iteration 2: draw the flappy
// Iteration 2: draw the pipes
this.bird.draw();
// Iteration 3: draw the pipes
this.pipes.forEach(p => p.draw());


// Bonus: draw the score

this.drawPipesCount++;
Expand Down
19 changes: 18 additions & 1 deletion assets/js/models/pipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Pipe {
this.mode = mode;

this.img = new Image();
// iteration 3: load the source checking the mode and setup this.with (must be the image with)
// iteration 3: load the source checking the mode and setup this.width (must be the image width)
this.img.src = `assets/img/pipe-${mode}.png`;
this.img.onload = () => {
this.width = this.img.width;
Expand All @@ -18,9 +18,26 @@ class Pipe {

draw() {
// iteration 3: draw the pipe don't worry if looks unscaled. You can start drawing a green rectangle
let yCrop = 0;

if(this.mode === "top") {
yCrop = (this.height > this.img.height) ? 0 : this.img.height - this.height;
}

this.ctx.drawImage(this.img,
0,
yCrop,
Math.min(this.img.width, this.width),
Math.min(this.img.height, this.height),
this.x,
this.y,
this.width,
this.height
);
}

move () {
// iteration 3: move the pipe
this.x -= this.vx;
}
}
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ <h1>Flappybird</h1>
<script src="assets/js/constants.js"></script>
<script src="assets/js/models/pipe.js"></script>
<script src="assets/js/models/flappybird.js"></script>
<script src="assets/js/models/brackgorund.js"></script>
<script src="assets/js/models/background.js"></script>
<script src="assets/js/models/game.js"></script>
<script src="assets/js/index.js"></script>
</body>
Expand Down