diff --git a/README.md b/README.md index 4a885a1..3c159cc 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,45 @@ -# (reemplazar nombre de juego acá) +# (Plane Fight) UTN - Facultad Regional Buenos Aires - Materia Paradigmas de Programación ## Equipo de desarrollo: -- completar... -- completar... +- Ezequiel Reichel +- Camila Nicole Ramos Fariña +- Catalina Wierna +- Gabriel Juarez +- Gonzalo Leon Bolaña +## Capturas +"Cuphead" - Enemigo cuerpo a cuerpo - Enemigo a distancia: -## Capturas +![pepita](assets/cuphead.png) ![pepita](assets/alienQueSeMueve.png) ![pepita](assets/alienQueDispara.png) -![pepita](assets/golondrina.png) +Capturas juego: + +![pepita](assets/capturaJuego1.png) + +Diagrama estatico +![pepita](assets/diagramaEstaticoFinal.jpeg) ## Reglas de Juego / Instrucciones -(completar...) +El juego "Plane Fight" se basa en el combate aereo del *personaje principal* (nuestro amigo "Cuphead" en su avioneta) contra una serie de enemigos que pueden hacerle daño de distinta manera (enemigos con misiles que atacan a distancia y otros enemigos que "van a por el" atacando cuerpo a cuerpo). Cuphead posee una cantidad de vida (3 corazones, representados en la esquina izquierda superior de la pantalla) y los enemigos tambien tendran su correspondiente cantidad de vida. Si los enemigos (sin importar que sea del tipo cuerpo a cuerpo o a distancia) o las balas enemigas colisionan con el avion, este ultimo se vera perjudicado reduciendo su vida. *En la colision del avion con un elemento, se aplica polimorfismo con dichos elementos, esperando que los mismos entiendan/conozcan el mensaje de colisionar contra el avion* -## Controles: +¿Como se defiende Cuphead? +Nuestro personaje puede atacar a estos rivales mediante el disparo de balas, estas al impactar en los enemigos haran que su vida se reduzca en una unidad (hasta llegar a 0 y desaparecer). *Ambos enemigos entienden/conocen el mensaje de perderVida al colisionar con las balas de Cuphead, pero cada uno tiene su comportamiento correspondiente (se aplica polimorfismo).* + +La dificultad del juego se incrementara a medida que se maten enemigos. Cada X cantidad de enemigos asesinados, la fase cambiara, cambiando el tipo de enemigos que aparecen y luego en fases posteriores modificando tambien la velocidad tanto del movimiento de los enemigos cuerpo a cuerpo, como asi tambien la velocidad e intervalo de disparo de los enemigos a distancia. -- `W` para... +Al finalizar la partida (cuando el personaje principal muere, es decir, su vida es igual a cero) se calcula un score en base a los enemigos eliminados (cada tipo de enemigo otorga un puntaje distinto al ser ejecutado). + +ENEMIGOS: +- Cuerpo a Cuerpo: Genera daño cuando hay una colicion. +- Disparo a distancia: Se mantiene en el borde derecho y dispara proyectiles rectos (ojo, tampoco te acerques tanto que tambien genera daño si lo colisionas) + +El objetivo del personaje es la superviviencia en contra de los enemigos que vayan aparaciendo a lo largo del juego + +## Controles: +- `aswd` o "flechitas" para que el personaje principal se mueva por la pantalla +- `space` para que el personaje principal dispare proyectiles \ No newline at end of file diff --git a/assets/Biplane (1).png b/assets/Biplane (1).png new file mode 100644 index 0000000..d2bbd51 Binary files /dev/null and b/assets/Biplane (1).png differ diff --git a/assets/FINALDELJUEGO.jpg b/assets/FINALDELJUEGO.jpg new file mode 100644 index 0000000..a150f91 Binary files /dev/null and b/assets/FINALDELJUEGO.jpg differ diff --git a/assets/Hilda_Berg_Moon_Sprite(1).png b/assets/Hilda_Berg_Moon_Sprite(1).png new file mode 100644 index 0000000..8b0cec5 Binary files /dev/null and b/assets/Hilda_Berg_Moon_Sprite(1).png differ diff --git a/assets/Hilda_Berg_Moon_Sprite.png b/assets/Hilda_Berg_Moon_Sprite.png new file mode 100644 index 0000000..8b0cec5 Binary files /dev/null and b/assets/Hilda_Berg_Moon_Sprite.png differ diff --git a/assets/alienQueDispara.png b/assets/alienQueDispara.png new file mode 100644 index 0000000..d86628f Binary files /dev/null and b/assets/alienQueDispara.png differ diff --git a/assets/alienQueSeMueve.png b/assets/alienQueSeMueve.png new file mode 100644 index 0000000..902e5a7 Binary files /dev/null and b/assets/alienQueSeMueve.png differ diff --git a/assets/balaEnemigo.png b/assets/balaEnemigo.png new file mode 100644 index 0000000..dad4ab6 Binary files /dev/null and b/assets/balaEnemigo.png differ diff --git a/assets/bala_Enemigo.png b/assets/bala_Enemigo.png new file mode 100644 index 0000000..dad4ab6 Binary files /dev/null and b/assets/bala_Enemigo.png differ diff --git a/assets/capturaJuego1.png b/assets/capturaJuego1.png new file mode 100644 index 0000000..27df888 Binary files /dev/null and b/assets/capturaJuego1.png differ diff --git a/assets/cuphead.png b/assets/cuphead.png new file mode 100644 index 0000000..19dd884 Binary files /dev/null and b/assets/cuphead.png differ diff --git a/assets/diagramaEstaticoFinal.jpeg b/assets/diagramaEstaticoFinal.jpeg new file mode 100644 index 0000000..dd9bfd5 Binary files /dev/null and b/assets/diagramaEstaticoFinal.jpeg differ diff --git a/assets/finDelJuego.png b/assets/finDelJuego.png new file mode 100644 index 0000000..a82eda7 Binary files /dev/null and b/assets/finDelJuego.png differ diff --git a/assets/gameOver.png b/assets/gameOver.png new file mode 100644 index 0000000..62eb2fe Binary files /dev/null and b/assets/gameOver.png differ diff --git a/assets/heart_21 (2).png b/assets/heart_21 (2).png new file mode 100644 index 0000000..975cb41 Binary files /dev/null and b/assets/heart_21 (2).png differ diff --git a/assets/sky1.png b/assets/sky1.png new file mode 100644 index 0000000..b2b6dd1 Binary files /dev/null and b/assets/sky1.png differ diff --git a/assets/spaceMissiles_009.webp b/assets/spaceMissiles_009.webp new file mode 100644 index 0000000..84e69c1 Binary files /dev/null and b/assets/spaceMissiles_009.webp differ diff --git a/assets/spaceMissiles_015.png b/assets/spaceMissiles_015.png new file mode 100644 index 0000000..5e125bf Binary files /dev/null and b/assets/spaceMissiles_015.png differ diff --git a/assets/spaceMissiles_024.png b/assets/spaceMissiles_024.png new file mode 100644 index 0000000..ead5fce Binary files /dev/null and b/assets/spaceMissiles_024.png differ diff --git a/assets/untitled_59.png b/assets/untitled_59.png new file mode 100644 index 0000000..1fdd8ba Binary files /dev/null and b/assets/untitled_59.png differ diff --git a/avion.wlk b/avion.wlk new file mode 100644 index 0000000..3d31913 --- /dev/null +++ b/avion.wlk @@ -0,0 +1,349 @@ + +object avion { + var property vida = 3 + var property position = new MutablePosition(x=0,y=8) + var property enemigosEliminados = 0 + var property puntaje = 0 + const imamgenBalaPersonaje = "spaceMissiles_015.png" + + method image() = "cuphead.png" + + method hablar() = "Bienvenidos a mi juego..." + + method decirVida() = self.vida() + + method decirPuntos() = self.puntaje() + + method sumarPuntaje(enemigo){puntaje+=enemigo.puntaje()} + + method perderVida(x) { + vida -= 1 //Hay que aplicarle como minimo 0 + if(self.vida() == 0){ + game.removeVisual(self) + game.addVisual(fondoFinJuego2) + game.addVisual(fondoFinDelJuego) + game.addVisual(finDelJuego) + //sonidoGameOver.reproducirSonido() + } + } + + method disparar() { + const nuevaBala = new Bala(latitud=self.position().x(), altura =self.position().y() , imagen = imamgenBalaPersonaje, id = 0.randomUpTo(5000), esEnemigo=false) + game.addVisual(nuevaBala) + game.onTick(100,"disparo"+nuevaBala.id(),{nuevaBala.moveteDerecha()}) + game.whenCollideDo(nuevaBala, {elemento => + elemento.perderVida(nuevaBala) + }) + } + +} + +class Corazon { + const id + + method esCuerpoACuerpo() = false + method image() = "heart_21 (2).png" + method position() = new MutablePosition(x=id,y=9) + method desaparecer() = game.removeVisual(self) + method perderVida(x){} // lo entiende pero no hace nada + method colicionarContraAvion(){} // lo entiende pero no hace nada +} + +object fondoFinDelJuego { + + method position() = new MutablePosition(x=1,y=0) + + method image() = "gameOver.png" + +} + +object fondoFinJuego2{ + method position() = new MutablePosition(x=0,y=0) + + method image() = "finDelJuego.png" +} + +object paleta { + const property rojo = "FF0000FF" +} + +object finDelJuego { + + method position() = game.center() + + method text() = "Puntaje obtenido: " + avion.puntaje().toString() + + method textColor() = paleta.rojo() + + method perderVida(x){} // lo entiende pero no hace nada +} + +/*object bossFinal { + var property puntaje = 100 + method esCuerpoACuerpo() = false + var property esBala = false + var property position = new MutablePosition(x=14,y=2)// mientras menos velocidad, el enemigo se desplaza mas rapido + var property esEnemigo = true + var property vida = 5 + var property intervaloDisparo = 1500 + var property imagenBalaBoss = "spaceMissiles_024.png" + var property velocidadDisparo = 1000 + + method image()="Hilda_Berg_Moon_Sprite(1).png" + + method perderVida() { + vida -= 1 + if(self.vida()==0) { + avion.sumarPuntaje(self) + fase.sacarEnemigosVivos() + fase.sumarEliminados(self) + game.removeVisual(self) + + } + } + method disparar(){ + game.onTick(self.intervaloDisparo(), "disparoBoss", { + if(avion.estaVivo()){ + const nuevaBala = new Bala(latitud=self.position().x(), altura =0.randomUpTo(9) , imagen=imagenBalaBoss, esEnemigo=true,id = 0.randomUpTo(5000) ) + game.addVisual(nuevaBala) + game.onTick(self.velocidadDisparo(), "disparoBoss1"+nuevaBala.id(), { nuevaBala.moveteIzquierda() }) + const nuevaBala = new Bala(latitud=self.position().x(), altura =0.randomUpTo(9) , imagen=imagenBalaBoss, esEnemigo=true,id = 0.randomUpTo(5000) ) + game.addVisual(nuevaBala) + game.onTick(self.velocidadDisparo(), "disparoBoss2"+nuevaBala.id(), { nuevaBala.moveteIzquierda() }) + const nuevaBala = new Bala(latitud=self.position().x(), altura =0.randomUpTo(9) , imagen=imagenBalaBoss, esEnemigo=true,id = 0.randomUpTo(5000) ) + game.addVisual(nuevaBala) + game.onTick(self.velocidadDisparo(), "disparoBoss3"+nuevaBala.id(), { nuevaBala.moveteIzquierda() }) + const nuevaBala = new Bala(latitud=self.position().x(), altura =0.randomUpTo(9) , imagen=imagenBalaBoss, esEnemigo=true,id = 0.randomUpTo(5000) ) + game.addVisual(nuevaBala) + game.onTick(self.velocidadDisparo(), "disparoBoss4"+nuevaBala.id(), { nuevaBala.moveteIzquierda() }) + } + }) + + } +}*/ + +//object sonidoGameOver { +// method reproducirSonido(){ +// game.sound("water-drop-sound.mp3").play() +// } +//} + +class EnemigoCuerpoACuerpo { + var property puntaje = 5 + var property position = new MutablePosition(x=19,y=0.randomUpTo(10)) // Para que arranque en alguna posicion del borde + var property velocidad = 1000 // mientras menos velocidad, el enemigo se desplaza mas rapido + var property vida = 5 + var property id + + method cambiarVelocidad() {velocidad = 100.max(velocidad-50)} //Hay que pensar un minimo (pensamos 100) + + method image() = "alienQueSeMueve.png" + + method colicionarContraAvion() {self.reaparecerAlaDerecha() avion.perderVida(id)} + + method reaparecerAlaDerecha() {position = new MutablePosition(x=18,y=0.randomUpTo(10))} + + method despalzamiento(){ + game.onTick(self.velocidad(), "movimiento"+self.id(), { self.movete() }) + } + + method movete(){ // se desplaza uno para la izquierda + position.goLeft(1) + + if(position.x() < 0) { + self.reaparecerAlaDerecha() + } + } + + method perderVida(nuevaBala) { + vida -= 1 + if(self.vida()==0) { + avion.sumarPuntaje(self) + fase.sacarEnemigosVivos() + fase.sumarEliminados(self) + game.removeTickEvent("movimiento"+self.id()) + game.removeVisual(self) + } + nuevaBala.eliminarBala() + } +} + + +class EnemigoPistolero { + const imagenBalaPistolero = "bala_Enemigo.png" + var property position = game.at(17,0.randomUpTo(10)) // Para que arranque en alguna posicion del borde + var property vida = 3 + var property intervaloDisparo = 2000 // mientras menos, el intervalo entre cada bala es mas rapido + var property velocidadDisparo = 250 // mientras menos, la velocidad de las balas es mas rapida + var property puntaje = 7 + var property id + + + method cambiarIntervaloDisparo() {intervaloDisparo = 1000.max(intervaloDisparo-100)} //Hay que pensar un minimo (pensamos 100) + + method cambiarVelocidadDisparo() {velocidadDisparo = 100.max(velocidadDisparo-25)} + + method colicionarContraAvion() {avion.perderVida(id)} + + method image() = "alienQueDispara.png" + + method disparar(){ + + game.onTick(self.intervaloDisparo(), "disparoEnemigo1"+self.id(), { + if(avion.vida()>0){ + const nuevaBala = new Bala(latitud=self.position().x(), altura =self.position().y() , imagen=imagenBalaPistolero,id = 0.randomUpTo(5000), esEnemigo=true) + game.addVisual(nuevaBala) + game.onTick(self.velocidadDisparo(), "disparoEnemigo2"+nuevaBala.id(), { nuevaBala.moveteIzquierda() }) + } + }) + + } + + method perderVida(nuevaBala) { + vida -= 1 + if(self.vida()==0) { + avion.sumarPuntaje(self) + fase.sacarEnemigosVivos() + fase.sumarEliminados(self) + game.removeTickEvent("disparoEnemigo1"+self.id()) + game.removeVisual(self) + } + nuevaBala.eliminarBala() + } + +} + + +class Bala { + var property latitud + var property altura + var property position = new MutablePosition(x=latitud,y=altura) + var property imagen + var property id + const esEnemigo + + method image() = imagen + + method perderVida(nuevaBala) {} // lo entiende pero no hace nada + + method vida () = 3 + + method eliminarBala(){ + position = new MutablePosition(x=100,y=100) + game.removeTickEvent("disparo"+self.id()) + game.removeVisual(self) + } + method moveteDerecha() { + if(position.x() < 20) { + position.goRight(1) + } + else { + self.eliminarBala() + } + } + + method moveteIzquierda(){ + if(position.x() > 0) { + position.goLeft(1) + } + else { + game.removeTickEvent("disparoEnemigo2"+self.id()) + game.removeVisual(self) + } + } + method colicionarContraAvion() { + if(esEnemigo){ + avion.perderVida(id) + } + game.removeTickEvent("disparoEnemigo2"+self.id()) + game.removeVisual(self) + } + +} + +object fase { + var property tiempoAparicion = 4000 //miliseg + var property maxEnemigos = 4 + var property enemigosVivos = 0 + var property nroFase = 1 + var property eliminacionesCambioFase = 6 + var property enemigosEliminadosFase = 0 + + + method sumarEliminado() { + enemigosEliminadosFase += 1 + } + + method reiniciarEliminados(){ + enemigosEliminadosFase = 0 + } + + method sumarEliminados(enemigo){ + + self.sumarEliminado() + + } + + method cambiarFase() { + if(nroFase < 3){ + nroFase += 1 + self.reiniciarEliminados() + } + else { + self.cambiarTiempoAparicion() + self.cambiarEnemigosMax() + + EnemigoCuerpoACuerpo.cambiarVelocidad() + EnemigoPistolero.cambiarIntervaloDisparo() + EnemigoPistolero.cambiarVelocidadDisparo() + + nroFase = 1 + + } + + } + + method cambiarTiempoAparicion() { + if(tiempoAparicion > 1000) tiempoAparicion -= 1000 + } + + method cambiarEnemigosMax(){ + if(maxEnemigos<12) maxEnemigos += 3 + } + + method agregarCuerpoACuerpo () { + if ((nroFase == 1 or nroFase==3) and avion.vida()>0){ //Usar contador de vida + const nuevoEnemigoCuerpo = new EnemigoCuerpoACuerpo(id = 0.randomUpTo(5000)) + game.addVisual(nuevoEnemigoCuerpo) + self.sumarEnemigosVivos() + nuevoEnemigoCuerpo.despalzamiento() + } + + } + + method agregarPistolero (){ //el ovni + if ((nroFase == 2 or nroFase==3) and avion.vida()>0){ + const nuevoEnemigoPistolero = new EnemigoPistolero(id = 0.randomUpTo(5000)) + game.addVisual(nuevoEnemigoPistolero) + self.sumarEnemigosVivos() + nuevoEnemigoPistolero.disparar() + } + } + + /*method agregarBoss (){ + if(nroFase == 4 and avion.estaVivo()){ + game.addVisual(bossFinal) + bossFinal.disparar() + self.sumarEnemigosVivos() + } + }*/ + + method sumarEnemigosVivos() { + enemigosVivos += 1 + } + + method sacarEnemigosVivos() { + enemigosVivos -= 1 + } + +} \ No newline at end of file diff --git a/main.wpgm b/main.wpgm index 4337325..eb0147f 100644 --- a/main.wpgm +++ b/main.wpgm @@ -1,16 +1,58 @@ import wollok.game.* -import pepita.* +import avion.* -program PepitaGame { - game.title("Pepita") +program PlaneFight { + + game.title("Plane Fight") game.height(10) - game.width(10) + game.width(20) game.cellSize(100) + game.boardGround("sky1.png") + game.addVisualCharacter(avion) + const corazon0 = new Corazon(id=0) + const corazon1 = new Corazon(id=1) + const corazon2 = new Corazon(id=2) + game.addVisual(corazon0) + game.addVisual(corazon1) + game.addVisual(corazon2) + - game.addVisual(pepita) +//SOBRE EL PERSONAJE----------------------------------------------------------------------- - keyboard.w().onPressDo({ pepita.fly(1) }) +//COLICIONES + game.whenCollideDo(avion, { elemento => + //TODO usar polimorfismo en vez del if + elemento.colicionarContraAvion() + if(avion.vida()== 2) corazon2.desaparecer() else if(avion.vida() == 1) corazon1.desaparecer() else if(avion.vida()==0) corazon0.desaparecer() + + }) + + +//DISPARO + keyboard.space().onPressDo({ + avion.disparar() + }) + +//DIALOGOS + keyboard.h().onPressDo({game.say(avion,avion.hablar())}) + + keyboard.v().onPressDo({game.say(avion,avion.decirVida().toString())}) + + keyboard.p().onPressDo({game.say(avion,avion.decirPuntos().toString())}) + + +//SOBRE ENEMIGOS -------------------------------------------------------------------------------- + game.onTick(fase.tiempoAparicion(),"Aparicion enemigos de la Fase",{ + if (fase.enemigosEliminadosFase() > fase.eliminacionesCambioFase()){ //los enemigos eliminados por fase son los matados, que se comparan con la cantidad necesaria para cambiar de fase + fase.cambiarFase() + } + if(fase.maxEnemigos() > fase.enemigosVivos()){ + //fase.agregarBoss() + fase.agregarPistolero() + fase.agregarCuerpoACuerpo() + } + }) game.start() } diff --git a/pepita.wlk b/pepita.wlk deleted file mode 100644 index 8763973..0000000 --- a/pepita.wlk +++ /dev/null @@ -1,16 +0,0 @@ -object pepita { - var energy = 100 - const position = new MutablePosition(x=0, y=0) - - method image() = "golondrina.png" - method position() = position - - method energy() = energy - - method fly(minutes) { - energy = energy - minutes * 3 - position.goRight(minutes) - position.goUp(minutes) - } - -} \ No newline at end of file diff --git a/pruebas.wtest b/pruebas.wtest index 7342cd1..0d18e9b 100644 --- a/pruebas.wtest +++ b/pruebas.wtest @@ -1,9 +1,36 @@ -import pepita.* +import avion.* -describe "group of tests for pepita" { +describe "Tests de puntuaciones al matar un enemigo" { - test "pepita has initial energy" { - assert.equals(100, pepita.energy()) + test "Sumar 5 al matar un enemigo cuerpo a cuerpo" { + const nuevaBala = new Bala(latitud =0, altura = 0 , imagen = "spaceMissiles_015.png", id = 0.randomUpTo(5000), esEnemigo=false) + const nuevoEnemigoCuerpo = new EnemigoCuerpoACuerpo(id = 1) + nuevoEnemigoCuerpo.perderVida(nuevaBala) + nuevoEnemigoCuerpo.perderVida(nuevaBala) + nuevoEnemigoCuerpo.perderVida(nuevaBala) + nuevoEnemigoCuerpo.perderVida(nuevaBala) + nuevoEnemigoCuerpo.perderVida(nuevaBala) + assert.equals(5, avion.puntaje()) } + test "Sumar 7 al matar un enemigo pistolero" { + const nuevaBala = new Bala(latitud =0, altura = 0 , imagen = "spaceMissiles_015.png", id = 0.randomUpTo(5000), esEnemigo=false) + const nuevoEnemigoPistola = new EnemigoPistolero(id = 2) + nuevoEnemigoPistola.perderVida(nuevaBala) + nuevoEnemigoPistola.perderVida(nuevaBala) + nuevoEnemigoPistola.perderVida(nuevaBala) + assert.equals(7, avion.puntaje()) + } + +} + +describe "Tests de variacion de vida del personaje principal" { + + test "Restar vida al avion cuando nos impacta una bala enemiga" { + const nuevoEnemigoPistola = new EnemigoPistolero(id = 3) + const nuevaBalaEnemiga = new Bala(latitud=0, altura =0 , imagen="bala_Enemigo.png", id = 0.randomUpTo(5000), esEnemigo=true ) + nuevaBalaEnemiga.colicionarContraAvion() + assert.equals(2, avion.vida()) + assert.that(avion.vida() < 3) + } } \ No newline at end of file