Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WD-PT-SEPT-2024] - Selena Sánchez - FlappyBird #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
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", event => game.onKeyEvent(event));
document.addEventListener("keyup", event => game.onKeyEvent(event));

});
16 changes: 14 additions & 2 deletions assets/js/models/brackgorund.js → assets/js/models/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ class Background {
// 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;
Expand All @@ -26,11 +29,20 @@ class Background {

draw() {
// iteration 1: draw the static backgorund img

this.ctx.drawImage(this.bgImg, 0, 0, this.bgImg.width, this.bgImg.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.width <= 0) {
this.x = 0;
}
}
}
40 changes: 38 additions & 2 deletions assets/js/models/flappybird.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ class FlappyBird {

this.sprite = new Image();
this.sprite.src = 'assets/img/bird.png';

// sprite setup
this.sprite.horizontalFrameIndex = 0;
this.sprite.verticalFrameIndex = 0;
this.sprite.horizontalFrames = 3;
this.sprite.verticalFrames = 1;

this.sprite.onload = () => {
this.sprite.frameWith = Math.floor(this.sprite.width / this.sprite.horizontalFrames);
this.sprite.frameHeight = Math.floor(this.sprite.height / this.sprite.verticalFrames);
Expand All @@ -29,25 +31,59 @@ class FlappyBird {
switch (event.keyCode) {
case KEY_UP:
// iteration 2: jump! if necessary =D
if (isJumping) {
this.y -= this.jumpImpulse;
}
break;
}
}

draw() {
// draw sprite

this.ctx.drawImage(
this.sprite,
(this.sprite.horizontalFrameIndex / this.sprite.horizontalFrames) * this.sprite.width,
0,
this.sprite.width / this.sprite.horizontalFrames,
this.sprite.height,
this.x,
this.y,
this.width,
this.height
)

this.drawCount++;

// animate sprite
this.animate();
}

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

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

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

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

collides(element) {
// iteration 3: check collisions (true|false)
const colX = this.x + this.width > element.x
&& this.x < element.x + element.width;
const colY = this.y + this.height > element.y
&& this.y < element.y + element.height;

return colX && colY;
}

}
94 changes: 88 additions & 6 deletions assets/js/models/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,79 +9,161 @@ class Game {
this.drawIntervalId = undefined;
this.fps = 1000 / 60;

// iteration 1: setup the background

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

// iteration 2: setup the flappy
this.flappybird = new FlappyBird(this.ctx, 50, Math.floor(this.canvas.height / 2));

this.pipes = [];
this.drawPipesCount = 0;
this.pipesFrequency = 100;

// bonus: setup the score
this.score = 0;
this.onGameEnd = onGameEnd;
}


onKeyEvent(event) {
// iteration 2: link flappy key events
this.flappybird.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.drawPipesCount++;

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

this.addPipes();
this.pipes.forEach((pipe) => {
pipe.draw();
pipe.move();
})
}
this.checkCollisions();
this.checkScore();

}, this.fps);
}
}

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

restart() {
// Bonus: restart on demand
this.pipes = [];
this.flappybird.x = 50;
this.flappybird.y = Math.floor(this.canvas.height / 2);
this.score = 0;
this.start();
}

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

const restartLogo = new Image();
restartLogo.src = 'assets/img/restart.png';

//onload to make sure the image is loaded
restartLogo.onload = () => {
this.ctx.drawImage(
restartLogo,
Math.floor((this.canvas.width - restartLogo.width) / 2),
Math.floor((this.canvas.height - restartLogo.height) / 2));
};
}

clear() {
// Iteration 1: clean the screen
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
//Remove the pipes with x less than 0
this.pipes = this.pipes.filter((pipe) => pipe.x + pipe.width >= 0);
}

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

addPipes() {
// Iteration 3: each draw pipes frequency cycles concat a pair of pipes to the pipes array and reset the draw cycle
this.pipes = this.pipes.concat(this.randPairOfPipes());
this.drawPipesCount = 0;
}

randPairOfPipes() {
const space = this.canvas.height - this.background.footerImg.height;
const gap = (this.flappybird.height * 2) + this.flappybird.jumpImpulse;
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, this.canvas.height - this.background.footerImg.height - bottomSize, bottomSize, 'bottom'),
]
}

checkCollisions() {
// Iteration 4: check pipes collisions among flappy and end game if any pipe collides with the bird
this.pipes.forEach(pipe => {
if (this.flappybird.collides(pipe)) {
this.end();
}
})

if ((this.flappybird.y + this.flappybird.height) >= this.background.y || this.flappybird.y <= 0) {
this.end();
}


}

checkScore() {
// Bonus
for (let i = 0; i < this.pipes.length / 2; i += 2) {
const pipe = this.pipes[i];
//isScored() checks if these pipes has been scored
if (this.flappybird.x > pipe.x + pipe.width && !pipe.isScored) {
this.score++;
pipe.isScored = true;
this.pipes[i+1].isScored = true;
}
}
}

draw() {
// Iteration 1: draw the background
this.background.draw();

// Iteration 2: draw the flappy
this.flappybird.draw();

// Iteration 2: draw the pipes
this.pipes.forEach(pipe => pipe.draw());
this.drawPipesCount++;

this.ctx.save();
// Bonus: draw the score
this.ctx.fillStyle = "white";
this.ctx.font = "25px FlappyFont";
this.ctx.fillText(this.score, 15, 30);

this.ctx.restore();

this.drawPipesCount++;
}
}
29 changes: 29 additions & 0 deletions assets/js/models/pipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,45 @@ class Pipe {
this.img = new Image();
// iteration 3: load the source checking the mode and setup this.with (must be the image with)
this.img.src = `assets/img/pipe-${mode}.png`;

this.img.onload = () => {
this.width = this.img.width;
}

this.isScored = false; //To check the score in the game
}

draw() {
// iteration 3: draw the pipe don't worry if looks unscaled. You can start drawing a green rectangle
let imgCropY = 0;
if (this.img.complete) {
switch(this.mode) {
case 'top':
//If height parameter is less than the height of the image, crop the img
imgCropY = (this.height <= this.img.height) ? this.img.height - this.height : 0;
break;
case 'bottom':
imgCropY = 0; //In Bottom Mode don't crop the image
break;
}

this.ctx.drawImage(
this.img,
0,
imgCropY,
this.width,
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