Skip to content

Trabajo Practico final - Programacion Orientada a Objetos ITBA (1er cuatrimestre 2019)

Notifications You must be signed in to change notification settings

pipo-co/TPE-POO

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

T.P. final POO

Fecha de entrega: 10/07/2019

Integrantes:

Modificaciones al programa provisto

En la clase cell se agregaron los métodos isCombinable, que indica si el contenido de la celda es combinable, y el método isBottom, que se fija si la celda se encuentra al fondo del tablero. En la clase abstracta Element se agregaron los métodos isCombinable, que indica si el elemento puede formar figuras válidas, isExpirable que indica si el elemento tiene una cantidad de movimientos fija antes de que ocurra algo, y por último hasBonus que indica si al romper el elemento se obtendrá algún beneficio extra. Estos se crearon con la intención de diferenciar las distintas propiedades que caracterizan a los nuevos elementos agregados. En las distintas clases que heredan de Element se les seteo el correspondiente valor a dichos métodos. Por ejemplo, se hizo que el método isCombinable de la clase Nothing devuelve false ya que no tendría sentido que pueda formar figuras válidas. Se decidió que las clases de estado que extienden de GameState dejen de ser inner-classes de los niveles para poder relacionarlas entre sí, ya que comparten funcionalidad, y que sus métodos puedan ser accedidos por otras clases que no son Level. De la clase Level1 se quitó el método fillCells (antes abstracto en Grid), pues se consideró que era un método que todos los niveles iban a implementar de manera muy similar. Es por esto que el método dejó de ser abstracto en Grid y se lo implementó allí. A su vez, tryMove era sobreescrito en Level1 solamente para incrementar la cantidad de movimientos en su GameState, funcionalidad que todos los niveles deben tener. Por lo tanto, se decidió agregar esta acción al método padre en Grid. En CandyGame se convirtió el método getSize a un método de clase ya que no usaba ninguna propiedad de instancia. Se quitaron los métodos isFinished y playerWon, pues en el diseño final del programa, debido a la implementación de las clases LevelInfo, se terminaron no usando. Ahora CandyGame recibe el nivel directamente instanciado, no su clase. En Grid se agregó el método estático inBounds que indica si un par de coordenadas están dentro del Grid. Se modificó el método initialize para poder modularizar lo que ocurría al generarse una nueva Grid. Para ello se agregaron los métodos cellCreator que indica que tipo de celda utiliza el nivel y setCandyCellGenerator, setFigureDetector y setMoveMaker que se ocupan de instanciar la implementación adecuada para cada nivel de cada una. Se eliminó el método removeFigure, ya que era una implementación muy similar a la de figureDetector y consideramos que se podía evitar la repetición de código. Se creó el getter de GameState, el método finish que se ejecuta cuando se finaliza un nivel para terminar sus procesos activos y el método getCurrentMoves que le pide al GameState la cantidad de movimientos actuales. En BoardPanel se agregaron dos métodos setImage nuevos, uno que además recibe un String para ser superpuesto a la imagen, y otro que ofrece la funcionalidad anterior más la posibilidad de aplicar un efecto a la celda. En CandyFrame se eliminó el getter del CandyGame ya que no se necesitaba, y toda la funcionalidad que se encargaba de refrescar la pantalla fue trasladada a ScreenUpdater. Además, se le agregó funcionalidad para que una vez terminado el juego no se puedan seguir haciendo movimientos, y la posibilidad de cambiar de nivel. Se cambió el nombre de ScorePanel a GameInfoPanel porque nos pareció que reflejaba mejor su funcionalidad. En la clase TwoWrappedCandyMove se modificó la implementación de removeElements por dos razones. Primero para evitar la repetición de código que había. Luego, se corrigió la forma en la que realizaba la explosión, ya que la misma no quitaba los dos caramelos que conformaban el movimiento, dando lugar a múltiples explosiones.

Se agregaron las siguientes clases:

  • SpecialItemAndCandyGenerator: Generador de caramelos que tiene la funcionalidad extra de crear un elemento especial especificado por el SpecialItemLevel que lo usa. En un principio se genera una cantidad inicial aleatoria en pantalla, y luego se siguen generando cada cierta cantidad de movimientos.
  • ConditionalRemovalCell : Celda donde su contenido se borra solo si se cumple con un criterio especificado por el ConditionalCellRemovalLevel que lo usa.
  • LightableCell: Celda especial que tiene la funcionalidad de “iluminarse” luego de ejecutarse un movimiento válido. Se creó para la implementación del nivel 2.
  • BonusTimeEnum: Lista los posibles valores de tiempo bonus con los que puede generarse un TimeCandy en el nivel 4.
  • TimeCandy: Caramelo que que posee un bonus de tiempo. Se utiliza en el nivel 4
  • MoveLimits: Lista los posibles valores que un ExpirableCandy puede tener en el nivel 3. Dicho valor indica cuantos movimientos pueden pasar antes de que el caramelo expire.
  • ExpirableCandy: Caramelo que expira si se alcanza su movimiento de expiración. Cuando se crea se guarda en qué movimiento se romperá sumando el movimiento en que se creó con su límite de movimientos.
  • FruitType: Lista los posibles tipos de un Fruit.
  • Fruit: Elemento que no puede ser combinado y solo se destruye cuando llega a la última fila de la matriz. Se utilizan en el nivel 5.

Se generaron los respectivos LevelState con la información pertinente a cada nivel como condición de ganar y de perder, entre otras.

  • Se crearon las clases abstractas MovementDependantState que representa aquellos niveles donde se perderá si no se ha ganado después de un determinado número de movimientos y se necesita saber cuántos movimientos le queda al jugador. ScoreDependantState que representa aquellos niveles donde se ganará si el jugador consigue obtener un determinado puntaje.
  • Level1State: extiende de MovementDependantState y ganará si se llega a un determinado Score.
  • Level2State: extiende de MovementDependantState y tiene cuantas celdas hay iluminadas actualmente y el total de celdas a iluminar, el jugador ganará cuando se hayan iluminado todas las celdas.
  • Level3State: extiende de ScoreDependantState y tiene una variable donde se indica cual es el número de movimiento de expiración más cercano en caso de haber algún elemento expirable en el tablero. El jugador perderá si el número de movimientos realizados supera dicho movimiento.
  • Level4State: extiende de ScoreDependantState y tiene una variable donde se tiene el tiempo actual. El jugador perderá si dicho tiempo llega a cero.
  • Level5State: extiende de MovementDependantState. El jugador ganará si se consigue eliminar la cantidad de frutas indicadas.
  • Interfaz SpecialItemLevel: implementada por los niveles que poseen un special item.
  • Interfaz ConditionalRemovalCriteria: implementada por los niveles que desean remover las celdas solamente si se cumple un criterio.
  • Level2: En cada movimiento válido que se realiza se iluminará la fila en la dirección en la que se haya realizado el movimiento. Luego de cada tryMove, si se logró realizar dicho movimiento se ejecuta el método lightCell que “prende” todas las celdas de la correspondiente línea, sumando al contador de celdas prendidas de Level2State.
  • Level3: Implementa SpecialItemLevel. Se genera un mapa ordenado donde estan ordenados todos los movimientos de expiración de los elementos expirables del nivel y se chequea luego de cada tryMove que la firstKey restado a los movimientos actuales sea mayor que cero. Se le da la frecuencia y el tipo de elemento especial al SpecialItemAndCandyGenerator para generar los elementos expirables. Cada vez que se genera un caramelo expirable se agrega al map su movimiento de expiración.
  • Level4: Implementa SpecialItemLevel. Se genera un timer que le resta a una variable tiempo en uno a cada segundo. Se guardan el tiempo inicial del mismo, su intervalo, y el delay que tendrá antes de empezar. Luego de cada explosión, el nivel se fija si lo que se rompió fue un elemento con bonus de tiempo y en ese caso se le suma al timer. Se le da la frecuencia y el tipo de elemento especial al SpecialItemAndCandyGenerator para generar los elementos bonus.
  • Level5: Implementa SpecialItemLevel y ConditionalRemovalCriteria. Se tienen el total de frutas que se necesitan para ganar el nivel, se le da el criterio para poder removerse a las celdas, el cual será que un elemento sea movible y que sea combinable (en caso de ser un caramelo normal) o que llegue al final de la celda (en el caso de las frutas). Luego de cada movimiento se realiza un fruitRemoval que se fija que si una fruta llegó a la última fila del grid se remueve y se resta del total de frutas necesarias para ganar.
  • Se creó la clase abstracta LevelInfo con la que se busco tener un interlocutor entre el back-end y el front-end que se ocupe de tomar la información del primero y enviarla procesada al segundo. LevelInfo le pregunta al state si el juego terminó y porque lo hizo enviando un mensaje correspondiente si ganó o perdió, o enviando un String con la información del nivel (como por ejemplo el score). También posee los métodos getElementText, que devuelve el texto que corresponde superponer a la celda en cuestión, o null si no hay que hacerlo, hasToUpdateInfo que indica si en este nivel se deberá hacer un update constante de la información que se envía al front end, que por defecto retorna false, y getCellEffect que indica que tipo de efecto visual se le debe aplicar a la celda, por defecto retorna ningún efecto.
  • Se creó la clase abstracta MovementDependantInfo para aquellas clases que como informacion adicional, además del score, necesiten mostrar los movimientos restantes.
  • Level2Info: Agrega a la información auxiliar la cantidad de celdas que faltan por iluminar para ganar el nivel. También tiene un método que indica en caso de la celda estar iluminada el efecto que el BoardPanel debe aplicar a la celda.
  • Level3Info: Posee el método movementsLeft que se ocupa de devolver un string con cuantos movimientos faltan para perder en caso de haber un elemento expirable en el tablero o ilimitado en caso de no haberlo.
  • Level4Info: El método getElementText que se ocupa de devolver el string que se imprime en los elementos con bonus de tiempo. Tambien el metodo hasToUpdateInfo en este caso enviará true, ya que a cada segundo se deberá hacer un update en el ScreenUpdater. Además agrega a la información auxiliar el tiempo que le queda al jugador antes de perder.
  • Level5Info: Tiene el método fruitsLeft que retorna un String con un mensaje que indica cuántas frutas le quedan por romper al jugador para ganar la partida. Además agrega dicho mensaje a la información auxiliar. Se generó la clase MainMenu que presenta un menú con botones con el nombre de cada uno de los niveles y al presionarlos iniciaran dicho nivel. A su vez, una vez iniciado un nivel se presenta la funcionalidad de volver hacia atrás y elegir otro. Se creó la clase CellEffects que le indicarán en caso de necesitarlo al BoardPanel cuál será el efecto que deberá aplicarle a la imagen en una celda.
  • ScreenUpdater: Esta clase se encarga de refrescar la pantalla. Casi toda su funcionalidad estaba en CandyFrame, pero decidimos crear esta clase para mayor modularización.
  • Levels: Enum que contiene todos los niveles creados hasta el momento y su descripción, junto con un método para crear el correspondiente LevelInfo.

Dificultades:

Dentro de las dificultades, la principal y que se dio a lo largo de todo el trabajo fue la correcta separación del back-end con el front-end, se tomó la idea del programa provisto de utilización CandyGame como nexo (entre las clases de front-end y back-end) y se implementaron las clases LevelInfo para vincular la información pertinente al nivel. Sin embargo, como en la cursada no se profundizó el tema, no teníamos un diseño claro para aplicar. Entendemos que podrían existir mejores diseños. También se dieron situaciones en las que el uso de instanceof hubieran solucionado determinados problemas, pero se decidió buscar alternativas para mantener un mejor estilo de programación. En situaciones particulares, como en el caso del Level1State, se presentó el conflicto de la necesidad de una herencia múltiple, ya que podría extender tanto de ScoreDependantState como de MovementDependantState. Si bien sabemos que las interfaces existen para resolver este problema, no pudimos llevar a cabo un diseño que consideraramos adecuado. Al momento de fabricar los tests, no supimos cómo debería ser un correcto testeo, en particular debido al carácter aleatorio del juego. Se decidió generar tests con tableros fijos para mostrar ciertas funcionalidades. Durante la creación de los mismos, hubo dificultades a la hora de iniciar estos niveles utilizando el front-end implementado para los niveles que puede deberse a un bajo nivel de conocimiento en el área de javafx. Además, a la hora de testear el front-end no se supo cómo debía ser puesto a prueba. Por último, como se decidió que desde el nivel se debería poder volver al selector de niveles, nos encontramos con el problema de que, luego de cambiar varias veces de nivel, el juego funcionaba cada vez más lento, creemos que puede deberse que se mantiene el hilo de ejecución del nivel anterior. Se implementó el método finish con la intención de cortar esas ejecuciones, pero no creemos haberlo podido solucionar por completo.

Ejecución de Tests

Se crearon algunos tests para los niveles 2 y 5 fijando un tablero que permite probar ciertas funcionalidades características del nivel. Los resultados esperados de los tests se encuentran en testsResults. Para cambiar de test, en la clase BasicTest se debe cambiar la instancia del enum Tests que se crea.

About

Trabajo Practico final - Programacion Orientada a Objetos ITBA (1er cuatrimestre 2019)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages