464 lines
10 KiB
JavaScript
464 lines
10 KiB
JavaScript
const canvas = document.getElementById("lienzo");
|
|
const ctx = canvas.getContext("2d");
|
|
const width = (canvas.width = 288);
|
|
const height = (canvas.height = 512);
|
|
ctx.scale(1, 1);
|
|
|
|
const states = {
|
|
IDLE: 0,
|
|
RUNNING: 1,
|
|
GAMEOVER: 2,
|
|
};
|
|
|
|
const images = {};
|
|
|
|
const audiosFx = {};
|
|
|
|
|
|
// function cargarImagenes(images, callback) {
|
|
// const nombresImagenes = [
|
|
// "bg",
|
|
// "suelo",
|
|
// "tuberias",
|
|
// "flappybird",
|
|
// "logo",
|
|
// "ready",
|
|
// "gameover",
|
|
// "taptap",
|
|
// ];
|
|
// let imagenesCargadas = 0;
|
|
// nombresImagenes.forEach((nombre) => {
|
|
// const img = new Image();
|
|
// img.src = `./assets/${nombre}.png`;
|
|
// img.onload = () => {
|
|
// imagenesCargadas++;
|
|
// if (imagenesCargadas === nombresImagenes.length) {
|
|
// callback(); // Llamar al callback una vez que todas las imágenes estén cargadas
|
|
// }
|
|
// };
|
|
// images[nombre] = img;
|
|
// });
|
|
// }
|
|
|
|
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;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Llama a la función cargarRecursos para cargar imágenes y audios
|
|
cargarRecursos(images, audiosFx, iniciarJuego);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
});
|
|
this.suelo.velocidad = 1;
|
|
}
|
|
}
|
|
|
|
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 {
|
|
constructor() {
|
|
this.sueloImg = images["suelo"];
|
|
this.posX = 0;
|
|
this.posY = height - this.sueloImg.height;
|
|
this.velocidad = 1;
|
|
}
|
|
update() {
|
|
this.posX -= this.velocidad;
|
|
if (this.posX + this.sueloImg.width === 0) this.posX = 0;
|
|
}
|
|
draw() {
|
|
ctx.drawImage(this.sueloImg, this.posX, this.posY);
|
|
ctx.drawImage(this.sueloImg, this.posX + width, this.posY);
|
|
}
|
|
}
|
|
|
|
class Tuberia {
|
|
constructor(posX, tipo) {
|
|
this.tuberiaImg = images["tuberias"];
|
|
this.tipo = tipo;
|
|
this.width = 52;
|
|
this.height = 320;
|
|
this.initialPosX = posX;
|
|
this.puntuada = false;
|
|
this.inicializa();
|
|
}
|
|
|
|
inicializa() {
|
|
this.separacion = 100;
|
|
this.velocidad = 0;
|
|
this.posX = this.initialPosX;
|
|
this.posY =
|
|
Math.floor(Math.random() * (300 - 100 + 1)) +
|
|
100 -
|
|
Math.floor(this.height * 2 + this.separacion) / 2;
|
|
}
|
|
|
|
generaPos() {
|
|
this.puntuada = false;
|
|
this.posX = width;
|
|
this.posY =
|
|
Math.floor(Math.random() * (300 - 100 + 1)) +
|
|
100 -
|
|
Math.floor(this.height * 2 + this.separacion) / 2;
|
|
}
|
|
|
|
update() {
|
|
this.posX -= this.velocidad;
|
|
if (this.posX <= 0 - this.width) {
|
|
this.generaPos();
|
|
}
|
|
}
|
|
|
|
draw() {
|
|
ctx.drawImage(
|
|
this.tuberiaImg,
|
|
1 * this.width,
|
|
this.tipo * this.height,
|
|
this.width,
|
|
this.height,
|
|
this.posX,
|
|
this.posY,
|
|
this.width,
|
|
this.height
|
|
);
|
|
ctx.drawImage(
|
|
this.tuberiaImg,
|
|
0 * this.width,
|
|
this.tipo * this.height,
|
|
this.width,
|
|
this.height,
|
|
this.posX,
|
|
this.posY + this.height + this.separacion,
|
|
this.width,
|
|
this.height
|
|
);
|
|
}
|
|
|
|
|
|
colision(bird){
|
|
if (
|
|
bird.posX + bird.width < xB || // Condición 1
|
|
bird.posX > this.posX + this.width || // Condición 2
|
|
bird.posY + hA < yB || // Condición 3
|
|
bird.posY > yB + hB // Condición 4
|
|
) {
|
|
// No hay colisión
|
|
return false;
|
|
} else {
|
|
// Hay colisión
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
superada(bird) {
|
|
if (bird.posX > this.posX + this.width && this.puntuada === false) {
|
|
this.puntuada = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class Bird {
|
|
constructor() {
|
|
this.birdImg = images["flappybird"];
|
|
this.width = 34;
|
|
this.height = 24;
|
|
this.nFramesAnim = 3;
|
|
this.animFrame = 0;
|
|
this.gameFrame = 0;
|
|
this.inicializa();
|
|
}
|
|
inicializa() {
|
|
this.posY = height / 2;
|
|
this.posX = width / 8;
|
|
this.gravedad = 0;
|
|
this.velY = 0;
|
|
}
|
|
impulsar() {
|
|
this.velY = -4;
|
|
}
|
|
update() {
|
|
this.velY += this.gravedad;
|
|
this.posY += this.velY;
|
|
this.animFrame = Math.floor(this.gameFrame / 10) % this.nFramesAnim;
|
|
this.gameFrame++;
|
|
}
|
|
draw() {
|
|
if (this.velY === 0) {
|
|
ctx.drawImage(
|
|
this.birdImg,
|
|
this.animFrame * this.width,
|
|
0,
|
|
this.width,
|
|
this.height,
|
|
this.posX,
|
|
this.posY,
|
|
this.width,
|
|
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;
|
|
}
|
|
for (let i = 0; i < tuberias.length; i++) {
|
|
const tuberia = tuberias[i];
|
|
if (
|
|
this.posX + this.width > tuberia.posX &&
|
|
this.posX < tuberia.posX + tuberia.width &&
|
|
(this.posY < tuberia.posY + tuberia.height ||
|
|
this.posY + this.height >
|
|
tuberia.posY + tuberia.height + tuberia.separacion)
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pasaTuberia(tuberias) {
|
|
if (tuberias[0].superada(this) || tuberias[1].superada(this)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function iniciarJuego() {
|
|
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(timeStamp) {
|
|
ctx.clearRect(0, 0, width, height);
|
|
ctx.drawImage(images["bg"], 0, 0, width, height);
|
|
|
|
if (
|
|
sprites[0].detectarColisiones([sprites[1], sprites[2]], sprites[3]) &&
|
|
state.state !== "GAMEOVER"
|
|
) {
|
|
audiosFx["gameover"].play();
|
|
console.log('paso');
|
|
state = new StateGameOver(sprites);
|
|
state.enter();
|
|
}
|
|
|
|
sprites.forEach((sprite) => {
|
|
sprite.update();
|
|
sprite.draw();
|
|
});
|
|
if (sprites[0].pasaTuberia([sprites[1], sprites[2]])) {
|
|
audiosFx["coin"].play();
|
|
puntuacion++;
|
|
}
|
|
ctx.fillText(puntuacion, 4, 30);
|
|
requestAnimationFrame(gameLoop);
|
|
}
|
|
|
|
gameLoop();
|
|
}
|
|
|
|
//cargarImagenes(images, iniciarJuego);
|
|
cargarRecursos(images,audiosFx,iniciarJuego);
|