Compare commits
No commits in common. "1042050308fba2747c5b6d5b4ba4e63530d38834" and "7a08b80e873bbd52727318046e99e698f7c3dc5e" have entirely different histories.
1042050308
...
7a08b80e87
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"liveServer.settings.port": 5501
|
|
||||||
}
|
|
||||||
BIN
assets/PngItem_2298804.png
Normal file
BIN
assets/PngItem_2298804.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
assets/coin.ogg
BIN
assets/coin.ogg
Binary file not shown.
BIN
assets/flap.ogg
BIN
assets/flap.ogg
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 5.0 KiB |
BIN
assets/logo.png
BIN
assets/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 4.6 KiB |
BIN
assets/ready.png
BIN
assets/ready.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB |
BIN
flappy-bird-master.zip
Normal file
BIN
flappy-bird-master.zip
Normal file
Binary file not shown.
380
game.js
380
game.js
|
|
@ -1,177 +1,25 @@
|
||||||
const canvas = document.getElementById("lienzo");
|
const canvas = document.getElementById("lienzo");
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
const width = (canvas.width = 288);
|
const width = (canvas.width = 288);
|
||||||
const height = (canvas.height = 512);
|
const height = (canvas.height = 512);
|
||||||
ctx.scale(1, 1);
|
|
||||||
|
|
||||||
const states = {
|
const sprites = [];
|
||||||
IDLE: 0,
|
|
||||||
RUNNING: 1,
|
|
||||||
GAMEOVER: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
const images = {};
|
const background = new Image();
|
||||||
const audiosFx = {};
|
background.src = "./assets/bg.png";
|
||||||
|
|
||||||
function cargarRecursos(images, audioFx, callback) {
|
|
||||||
const recursos = [
|
|
||||||
{ nombre: "bg", tipo: "imagen" },
|
|
||||||
{ nombre: "suelo", tipo: "imagen" },
|
|
||||||
{ nombre: "tuberias", tipo: "imagen" },
|
|
||||||
{ nombre: "flappybird", tipo: "imagen" },
|
|
||||||
{ nombre: "logo", tipo: "imagen" },
|
|
||||||
{ nombre: "ready", tipo: "imagen" },
|
|
||||||
{ nombre: "gameover", tipo: "imagen" },
|
|
||||||
{ nombre: "taptap", tipo: "imagen" },
|
|
||||||
{ nombre: "gameover", tipo: "audio" },
|
|
||||||
{ nombre: "coin", tipo: "audio" },
|
|
||||||
{ nombre: "flap", tipo: "audio" },
|
|
||||||
];
|
|
||||||
let recursosCargados = 0;
|
|
||||||
|
|
||||||
recursos.forEach((recurso) => {
|
|
||||||
if (recurso.tipo === "imagen") {
|
|
||||||
const img = new Image();
|
|
||||||
img.src = `./assets/${recurso.nombre}.png`;
|
|
||||||
img.onload = () => {
|
|
||||||
recursosCargados++;
|
|
||||||
if (recursosCargados === recursos.length) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
images[recurso.nombre] = img;
|
|
||||||
} else if (recurso.tipo === "audio") {
|
|
||||||
const audio = new Audio();
|
|
||||||
audio.src = `./assets/${recurso.nombre}.ogg`;
|
|
||||||
audio.addEventListener("canplaythrough", () => {
|
|
||||||
recursosCargados++;
|
|
||||||
if (recursosCargados === recursos.length) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
audioFx[recurso.nombre] = audio;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class State {
|
|
||||||
constructor(state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StateIdle extends State {
|
|
||||||
constructor(sprites) {
|
|
||||||
super("IDLE");
|
|
||||||
this.bird = sprites[0];
|
|
||||||
this.tuberias = [sprites[1], sprites[2]];
|
|
||||||
sprites.push(new Ready(), new TapTap());
|
|
||||||
}
|
|
||||||
enter() {
|
|
||||||
this.bird.velY = this.bird.gravedad = 0;
|
|
||||||
this.tuberias.forEach((tuberia) => {
|
|
||||||
tuberia.velocidad = 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StateRunnig extends State {
|
|
||||||
constructor(sprites) {
|
|
||||||
super("RUNNING");
|
|
||||||
this.bird = sprites[0];
|
|
||||||
this.tuberias = [sprites[1], sprites[2]];
|
|
||||||
this.suelo = sprites[3];
|
|
||||||
sprites.splice(-2);
|
|
||||||
}
|
|
||||||
enter() {
|
|
||||||
this.bird.inicializa();
|
|
||||||
this.bird.velY = 0;
|
|
||||||
this.bird.gravedad = 0.2;
|
|
||||||
this.bird.nFramesAnim = 3;
|
|
||||||
this.tuberias.forEach((tuberia) => {
|
|
||||||
tuberia.inicializa();
|
|
||||||
tuberia.velocidad = 1.5;
|
|
||||||
});
|
|
||||||
this.suelo.velocidad = 1.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StateGameOver extends State {
|
|
||||||
constructor(sprites) {
|
|
||||||
super("GAMEOVER");
|
|
||||||
this.bird = sprites[0];
|
|
||||||
this.tuberias = [sprites[1], sprites[2]];
|
|
||||||
this.suelo = sprites[3];
|
|
||||||
sprites.push(new GameOver(), new TapTap());
|
|
||||||
}
|
|
||||||
enter() {
|
|
||||||
this.bird.velY = this.bird.gravedad = 0;
|
|
||||||
this.bird.nFramesAnim = 1;
|
|
||||||
this.tuberias.forEach((tuberia) => {
|
|
||||||
tuberia.velocidad = 0;
|
|
||||||
});
|
|
||||||
this.suelo.velocidad = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Logo {
|
|
||||||
constructor() {
|
|
||||||
this.logoImg = images["logo"];
|
|
||||||
this.posX = width / 2 - this.logoImg.width / 2;
|
|
||||||
this.posY = height - this.logoImg.height - 20;
|
|
||||||
}
|
|
||||||
update() {}
|
|
||||||
draw() {
|
|
||||||
ctx.drawImage(this.logoImg, this.posX, this.posY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Ready {
|
|
||||||
constructor() {
|
|
||||||
this.readyImg = images["ready"];
|
|
||||||
this.posX = width / 2 - this.readyImg.width / 2;
|
|
||||||
this.posY = height / 4 - this.readyImg.height / 2;
|
|
||||||
}
|
|
||||||
update() {}
|
|
||||||
draw() {
|
|
||||||
ctx.drawImage(this.readyImg, this.posX, this.posY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GameOver {
|
|
||||||
constructor() {
|
|
||||||
this.gameOverImg = images["gameover"];
|
|
||||||
this.posX = width / 2 - this.gameOverImg.width / 2;
|
|
||||||
this.posY = height / 4 - this.gameOverImg.height / 2;
|
|
||||||
}
|
|
||||||
update() {}
|
|
||||||
draw() {
|
|
||||||
ctx.drawImage(this.gameOverImg, this.posX, this.posY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TapTap {
|
|
||||||
constructor() {
|
|
||||||
this.tapTapImg = images["taptap"];
|
|
||||||
this.posX = width / 2 - this.tapTapImg.width / 2;
|
|
||||||
this.posY = height / 2 - this.tapTapImg.height / 2;
|
|
||||||
}
|
|
||||||
update() {}
|
|
||||||
draw() {
|
|
||||||
ctx.drawImage(this.tapTapImg, this.posX, this.posY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Suelo {
|
class Suelo {
|
||||||
constructor() {
|
constructor(ctx) {
|
||||||
this.sueloImg = images["suelo"];
|
this.ctx = ctx;
|
||||||
|
this.sueloImg = new Image();
|
||||||
|
this.sueloImg.src = "./assets/suelo.png";
|
||||||
this.posX = 0;
|
this.posX = 0;
|
||||||
this.posY = height - this.sueloImg.height;
|
this.posY = height - this.sueloImg.height;
|
||||||
this.velocidad = 1;
|
|
||||||
}
|
}
|
||||||
update() {
|
update() {
|
||||||
this.posX -= this.velocidad;
|
this.posX--;
|
||||||
if (this.posX + this.sueloImg.width <= 0) this.posX = 0;
|
if (this.posX + this.sueloImg.width === 0) this.posX = 0;
|
||||||
}
|
}
|
||||||
draw() {
|
draw() {
|
||||||
ctx.drawImage(this.sueloImg, this.posX, this.posY);
|
ctx.drawImage(this.sueloImg, this.posX, this.posY);
|
||||||
|
|
@ -180,20 +28,15 @@ class Suelo {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Tuberia {
|
class Tuberia {
|
||||||
constructor(posX, tipo) {
|
constructor(ctx, posX, tipo) {
|
||||||
this.tuberiaImg = images["tuberias"];
|
this.ctx = ctx;
|
||||||
|
this.tuberiaImg = new Image();
|
||||||
|
this.tuberiaImg.src = "./assets/tuberias.png";
|
||||||
this.tipo = tipo;
|
this.tipo = tipo;
|
||||||
this.width = 52;
|
this.width = 52;
|
||||||
this.height = 320;
|
this.height = 320;
|
||||||
this.initialPosX = posX;
|
this.separacion = 60; //min 60 max 120
|
||||||
this.puntuada = false;
|
this.posX = posX;
|
||||||
this.inicializa();
|
|
||||||
}
|
|
||||||
|
|
||||||
inicializa() {
|
|
||||||
this.separacion = 120;
|
|
||||||
this.velocidad = 0;
|
|
||||||
this.posX = this.initialPosX;
|
|
||||||
this.posY =
|
this.posY =
|
||||||
Math.floor(Math.random() * (300 - 100 + 1)) +
|
Math.floor(Math.random() * (300 - 100 + 1)) +
|
||||||
100 -
|
100 -
|
||||||
|
|
@ -201,7 +44,6 @@ class Tuberia {
|
||||||
}
|
}
|
||||||
|
|
||||||
generaPos() {
|
generaPos() {
|
||||||
this.puntuada = false;
|
|
||||||
this.posX = width;
|
this.posX = width;
|
||||||
this.posY =
|
this.posY =
|
||||||
Math.floor(Math.random() * (300 - 100 + 1)) +
|
Math.floor(Math.random() * (300 - 100 + 1)) +
|
||||||
|
|
@ -210,15 +52,14 @@ class Tuberia {
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
this.posX -= this.velocidad;
|
this.posX--;
|
||||||
if (this.posX <= 0 - this.width) {
|
if (this.posX <= 0 - this.width) {
|
||||||
this.aumentaDificultad();
|
|
||||||
this.generaPos();
|
this.generaPos();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
this.tuberiaImg,
|
this.tuberiaImg,
|
||||||
1 * this.width,
|
1 * this.width,
|
||||||
this.tipo * this.height,
|
this.tipo * this.height,
|
||||||
|
|
@ -229,7 +70,7 @@ class Tuberia {
|
||||||
this.width,
|
this.width,
|
||||||
this.height
|
this.height
|
||||||
);
|
);
|
||||||
ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
this.tuberiaImg,
|
this.tuberiaImg,
|
||||||
0 * this.width,
|
0 * this.width,
|
||||||
this.tipo * this.height,
|
this.tipo * this.height,
|
||||||
|
|
@ -241,72 +82,29 @@ class Tuberia {
|
||||||
this.height
|
this.height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
detectarColision(bird) {
|
|
||||||
const xA = bird.posX;
|
|
||||||
const yA = Math.floor(bird.posY);
|
|
||||||
const wA = bird.width;
|
|
||||||
const hA = bird.height;
|
|
||||||
|
|
||||||
const xB = this.posX;
|
|
||||||
const yB = this.posY;
|
|
||||||
const wB = this.width;
|
|
||||||
const hB = this.height;
|
|
||||||
|
|
||||||
const xC = this.posX;
|
|
||||||
const yC = this.posY + this.height + this.separacion;
|
|
||||||
const wC = this.width;
|
|
||||||
const hC = this.height;
|
|
||||||
|
|
||||||
const colisionConTuberia1 =
|
|
||||||
xA < xB + wB && xA + wA > xB && yA < yB + hB && yA + hA > yB;
|
|
||||||
|
|
||||||
const colisionConTuberia2 =
|
|
||||||
xA < xC + wC && xA + wA > xC && yA < yC + hC && yA + hA > yC;
|
|
||||||
|
|
||||||
return colisionConTuberia1 || colisionConTuberia2;
|
|
||||||
}
|
|
||||||
|
|
||||||
superada(bird) {
|
|
||||||
if (bird.posX > this.posX + this.width && this.puntuada === false) {
|
|
||||||
this.puntuada = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
aumentaDificultad() {
|
|
||||||
if (this.separacion >= 80) this.separacion--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Bird {
|
class Bird {
|
||||||
constructor() {
|
nFramesAnim = 3;
|
||||||
this.birdImg = images["flappybird"];
|
animFrame = 0;
|
||||||
this.width = 34;
|
gameFrame = 0;
|
||||||
this.height = 24;
|
constructor(ctx) {
|
||||||
this.nFramesAnim = 3;
|
this.gravedad = 0;
|
||||||
this.animFrame = 0;
|
this.ctx = ctx;
|
||||||
this.gameFrame = 0;
|
this.birdImg = new Image();
|
||||||
this.inicializa();
|
this.birdImg.src = "./assets/flappybird.png";
|
||||||
}
|
|
||||||
inicializa() {
|
|
||||||
this.posY = height / 2;
|
this.posY = height / 2;
|
||||||
this.posX = width / 8;
|
this.posX = width / 8;
|
||||||
this.gravedad = 0;
|
this.width = 34;
|
||||||
this.velY = 0;
|
this.height = 24;
|
||||||
}
|
|
||||||
impulsar() {
|
|
||||||
this.velY = -4;
|
|
||||||
}
|
}
|
||||||
update() {
|
update() {
|
||||||
this.velY += this.gravedad;
|
this.posY += this.gravedad;
|
||||||
this.posY += this.velY;
|
|
||||||
this.animFrame = Math.floor(this.gameFrame / 10) % this.nFramesAnim;
|
this.animFrame = Math.floor(this.gameFrame / 10) % this.nFramesAnim;
|
||||||
this.gameFrame++;
|
this.gameFrame++;
|
||||||
}
|
}
|
||||||
draw() {
|
draw() {
|
||||||
if (this.velY === 0) {
|
this.ctx.drawImage(
|
||||||
ctx.drawImage(
|
|
||||||
this.birdImg,
|
this.birdImg,
|
||||||
this.animFrame * this.width,
|
this.animFrame * this.width,
|
||||||
0,
|
0,
|
||||||
|
|
@ -317,116 +115,26 @@ class Bird {
|
||||||
this.width,
|
this.width,
|
||||||
this.height
|
this.height
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.save();
|
|
||||||
if (this.velY > 0) {
|
|
||||||
ctx.translate(this.posX + this.width / 2, this.posY + this.height / 2);
|
|
||||||
ctx.rotate((30 * Math.PI) / 180);
|
|
||||||
ctx.drawImage(
|
|
||||||
this.birdImg,
|
|
||||||
this.animFrame * this.width,
|
|
||||||
0,
|
|
||||||
this.width,
|
|
||||||
this.height,
|
|
||||||
-this.width / 2,
|
|
||||||
-this.height / 2,
|
|
||||||
this.width,
|
|
||||||
this.height
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ctx.translate(this.posX + this.width / 2, this.posY + this.height / 2);
|
|
||||||
ctx.rotate((-30 * Math.PI) / 180);
|
|
||||||
ctx.drawImage(
|
|
||||||
this.birdImg,
|
|
||||||
this.animFrame * this.width,
|
|
||||||
0,
|
|
||||||
this.width,
|
|
||||||
this.height,
|
|
||||||
-this.width / 2,
|
|
||||||
-this.height / 2,
|
|
||||||
this.width,
|
|
||||||
this.height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
detectarColisiones(tuberias, suelo) {
|
|
||||||
if (this.posY + this.height >= suelo.posY) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
tuberias[0].detectarColision(this) ||
|
|
||||||
tuberias[1].detectarColision(this)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pasaTuberia(tuberias) {
|
|
||||||
if (tuberias[0].superada(this) || tuberias[1].superada(this)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function iniciarJuego() {
|
function gameLoop(timeStamp) {
|
||||||
let bucle;
|
|
||||||
let puntuacion = 0;
|
|
||||||
ctx.font = "24px 'Press Start 2P'";
|
|
||||||
ctx.fillStyle = "white";
|
|
||||||
|
|
||||||
const sprites = [
|
|
||||||
new Bird(),
|
|
||||||
new Tuberia(width + 100, 1),
|
|
||||||
new Tuberia(width + 100 + width * 0.5 + 25, 0),
|
|
||||||
new Suelo(),
|
|
||||||
new Logo(),
|
|
||||||
];
|
|
||||||
|
|
||||||
let state = new StateIdle(sprites);
|
|
||||||
state.enter();
|
|
||||||
|
|
||||||
document.addEventListener("keydown", function (event) {
|
|
||||||
if (event.code === "Space") {
|
|
||||||
if (state.state === "IDLE" || state.state === "GAMEOVER") {
|
|
||||||
puntuacion = 0;
|
|
||||||
state = new StateRunnig(sprites);
|
|
||||||
state.enter();
|
|
||||||
}
|
|
||||||
sprites[0].impulsar();
|
|
||||||
audiosFx["flap"].play();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function gameLoop() {
|
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width, height);
|
||||||
ctx.drawImage(images["bg"], 0, 0, width, height);
|
ctx.drawImage(background, 0, 0, width, height);
|
||||||
sprites.forEach((sprite) => {
|
sprites.forEach((sprite) => {
|
||||||
sprite.update();
|
sprite.update();
|
||||||
sprite.draw();
|
sprite.draw();
|
||||||
});
|
});
|
||||||
if (sprites[0].pasaTuberia([sprites[1], sprites[2]])) {
|
requestAnimationFrame(gameLoop); // Llamar a gameLoop de nuevo en el siguiente fotograma
|
||||||
audiosFx["coin"].play();
|
|
||||||
puntuacion++;
|
|
||||||
}
|
|
||||||
ctx.fillText(puntuacion, 4, 30);
|
|
||||||
const colision = sprites[0].detectarColisiones(
|
|
||||||
[sprites[1], sprites[2]],
|
|
||||||
sprites[3]
|
|
||||||
);
|
|
||||||
if (colision && state.state !== "GAMEOVER") {
|
|
||||||
state = new StateGameOver(sprites);
|
|
||||||
state.enter();
|
|
||||||
audiosFx["gameover"].play();
|
|
||||||
window.cancelAnimationFrame(bucle);
|
|
||||||
}
|
|
||||||
bucle = requestAnimationFrame(gameLoop);
|
|
||||||
}
|
|
||||||
|
|
||||||
gameLoop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cargarRecursos(images, audiosFx, iniciarJuego);
|
sprites.push(
|
||||||
|
new Bird(ctx),
|
||||||
|
new Tuberia(ctx, width * 2, 1),
|
||||||
|
new Tuberia(ctx, width * 2 + width * 0.5 + 25, 0),
|
||||||
|
new Suelo(ctx)
|
||||||
|
);
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
gameLoop();
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,7 @@
|
||||||
<title>Flappy bird</title>
|
<title>Flappy bird</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="lienzo"></canvas> <br> <br>
|
<canvas id="lienzo"></canvas>
|
||||||
<a id="repositorioGit" href="https://git.marklogo.duckdns.org/" target="_blank"> <i class="ti ti-brand-github"></i> Repositorio Git</a>
|
|
||||||
</body>
|
</body>
|
||||||
<script src="./game.js"></script>
|
<script src="./game.js"></script>
|
||||||
</html>
|
</html>
|
||||||
11
style.css
11
style.css
|
|
@ -21,15 +21,4 @@ body {
|
||||||
background-color: #2c5364;
|
background-color: #2c5364;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
border: 4px solid white;
|
|
||||||
}
|
}
|
||||||
#repositorioGit {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #333;
|
|
||||||
color: #fff;
|
|
||||||
padding: 10px 20px;
|
|
||||||
text-decoration: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user