diff --git a/assets/PngItem_2298804.png b/assets/PngItem_2298804.png deleted file mode 100644 index e6d3bb7..0000000 Binary files a/assets/PngItem_2298804.png and /dev/null differ diff --git a/assets/coin.ogg b/assets/coin.ogg new file mode 100644 index 0000000..d278455 Binary files /dev/null and b/assets/coin.ogg differ diff --git a/assets/flap.ogg b/assets/flap.ogg new file mode 100644 index 0000000..2732cff Binary files /dev/null and b/assets/flap.ogg differ diff --git a/assets/gameover.ogg b/assets/gameover.ogg new file mode 100644 index 0000000..da98c64 Binary files /dev/null and b/assets/gameover.ogg differ diff --git a/assets/gameover.png b/assets/gameover.png new file mode 100644 index 0000000..63a01e9 Binary files /dev/null and b/assets/gameover.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..625bcaa Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/ready.png b/assets/ready.png new file mode 100644 index 0000000..dc18cc6 Binary files /dev/null and b/assets/ready.png differ diff --git a/assets/taptap.png b/assets/taptap.png new file mode 100644 index 0000000..af58267 Binary files /dev/null and b/assets/taptap.png differ diff --git a/game.js b/game.js index 684cdf9..5d19afc 100644 --- a/game.js +++ b/game.js @@ -1,24 +1,211 @@ 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 sprites = []; +const states = { + IDLE: 0, + RUNNING: 1, + GAMEOVER: 2, +}; -const background = new Image(); -background.src = "./assets/bg.png"; +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(ctx) { - this.ctx = ctx; - this.sueloImg = new Image(); - this.sueloImg.src = "./assets/suelo.png"; + constructor() { + this.sueloImg = images["suelo"]; this.posX = 0; this.posY = height - this.sueloImg.height; + this.velocidad = 1; } update() { - this.posX--; + this.posX -= this.velocidad; if (this.posX + this.sueloImg.width === 0) this.posX = 0; } draw() { @@ -28,15 +215,20 @@ class Suelo { } class Tuberia { - constructor(ctx, posX, tipo) { - this.ctx = ctx; - this.tuberiaImg = new Image(); - this.tuberiaImg.src = "./assets/tuberias.png"; + constructor(posX, tipo) { + this.tuberiaImg = images["tuberias"]; this.tipo = tipo; this.width = 52; this.height = 320; - this.separacion = 60; //min 60 max 120 - this.posX = posX; + 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 - @@ -44,6 +236,7 @@ class Tuberia { } generaPos() { + this.puntuada = false; this.posX = width; this.posY = Math.floor(Math.random() * (300 - 100 + 1)) + @@ -52,14 +245,14 @@ class Tuberia { } update() { - this.posX--; + this.posX -= this.velocidad; if (this.posX <= 0 - this.width) { this.generaPos(); } } draw() { - this.ctx.drawImage( + ctx.drawImage( this.tuberiaImg, 1 * this.width, this.tipo * this.height, @@ -70,7 +263,7 @@ class Tuberia { this.width, this.height ); - this.ctx.drawImage( + ctx.drawImage( this.tuberiaImg, 0 * this.width, this.tipo * this.height, @@ -82,59 +275,189 @@ class Tuberia { 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 { - nFramesAnim = 3; - animFrame = 0; - gameFrame = 0; - constructor(ctx) { - this.gravedad = 0; - this.ctx = ctx; - this.birdImg = new Image(); - this.birdImg.src = "./assets/flappybird.png"; - this.posY = height / 2; - this.posX = width / 8; + 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.posY += this.gravedad; + this.velY += this.gravedad; + this.posY += this.velY; this.animFrame = Math.floor(this.gameFrame / 10) % this.nFramesAnim; this.gameFrame++; } draw() { - this.ctx.drawImage( - this.birdImg, - this.animFrame * this.width, - 0, - this.width, - this.height, - this.posX, - this.posY, - this.width, - this.height - ); + 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 gameLoop(timeStamp) { - ctx.clearRect(0, 0, width, height); - ctx.drawImage(background, 0, 0, width, height); - sprites.forEach((sprite) => { - sprite.update(); - sprite.draw(); +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(); + } }); - requestAnimationFrame(gameLoop); // Llamar a gameLoop de nuevo en el siguiente fotograma + + 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(); } -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(); -}; +//cargarImagenes(images, iniciarJuego); +cargarRecursos(images,audiosFx,iniciarJuego);