Giter Site home page Giter Site logo

alpaca_emblem's Introduction

Alpaca_Emblem 2.5

El proyecto se encuentra en su versión 2.5 acorde a los requisitos de la entrega n°2.

En esta entrega se diseñaron las clases GameController y Tactician, junto con otras clases creadas para los patrones de diseño, como factories, handlers/listeners y un NullUnit. Se repetirán secciones de la entrega anterior para mostrar las updates de cada clase.

Tactician

Representa aun jugador, guardando los datos de este y siendo el intermediario entre el Game Controller y el resto del modelo (model). El Tactician tiene los siguientes atributos privados:

  • Nombre: name es un final String que corresponde al nombre del Tactician del jugador.
  • Unidades: units es un ArrayList que guarda las unidades del Tactican del jugador.
  • Unidades desplazadas: movedUnits es un ArrayList que guarda las unidades del Tactican desplazadas en ese turno por el jugador.
  • Unidad seleccionada: selectedUnit es un IUnit con la Unidad seleccionada del Tactician del jugador
  • Item seleccionado:selectedItem es un IEquipableItem con el item seleccionado del Tactician del jugador
  • Supports: Hay dos handlers (PropertyChangeSupport) uno para cuando el tactician pierde un Hero y otro para cuando pierde a otro tipo de unidad.

El tactician puede realizar lo siguiente: agregarse unidades, seleccionar unidades y guardarles o equiparles items, puede ver sus unidades, sus atributos y los de sus items, tambien intercambiar objetos entre ellas así como usar el item equipado en otras unidades. Puede mover sus unidades una vez por turno, por lo que se aplicó como estrategía que cada vez que el Tactician mueve una unidad, este lo guarda en movedUnits. Tambien puede remover totalmente sus unidades si el HP de estas llega a 0 y notificar que ha perdido al controler si alguno de sus Hero's muere o muere una de sus otras unidades (hará uso del Support para avisar al GameController).

Game Controller

Maneja todo los inputs dados por el jugador. Y tiene los siguientes atributos:

  • Tacticians: es un ArrayList con los tacticians en el juego (depende de cuantos jugadores se quieran en el juego), luego de crearse cada tactician se le suscribirá a un support.
  • Secuencia: es un ArrayList con los tacticians en el juego, pero reordenados según la seed y otras condiciones.
  • Mapa: es un Field, el mapa donde se desenvolverá el juego (random según la seed), depende del tamaño que se quiera.
  • Seed: es un long random, que se usará com semilla (para crear otra semilla) para la creación del Mapa y la Secuencia.
  • Ronda: es un int que corresponde al número de la ronda actual.
  • Rondas máximas: es un int que corresponde al número máximo de rondas en el juego actual, una vez la ronda llegue a este número el juego acaba.
  • Unidades máximas: Restricción ideada de forma personal, depende de la cantidad de jugadores y el tamaño del mapa.

El Game Controller puede inicializar un juego (con limite o sin limite), inicializar un juego generará una Secuencia, setea el roundNumber en 1 y asigna como turnOwner al primero en la Secuencia, tambien puede terminar un turno, con esto el siguiente turnOwner será el siguiente en la Secuencia y de haberse acabado esta se generará otra (imposibilitando que el que recién jugo juegue en el primer turno de la nueva ronda) y se sumará 1 a roundNumber.

El Game Controller puede remover tactician's del juego si estos llegan a declarar que perdieron, si se encuentran en su turno se pasará al siguiente jugador. Además puede declarar los ganadores del juego.

Como se dijo antes, el GameController recibe todos los inputs, por lo que tiene muchos métodos que adaptan el input para que sean entendibles para el Tactician (como los que tienen que ver con el mapa, el GameController recibe las coordenadas y le da al Tactician el Location) y otros métodos que simplemente deliveran la tarea al Tactician. Por lo que ElGamecontroller funciona como un Adapter para el Tactician.

Unidades:

Ahora también tienen una referencia al Tactician que les posee.

Esta entrega generó un problema respecto al combate, el GameController y el Tactician tienen un metodo que permite usar el item seleccionado en otra unidad, pero estos no tienen restricciones ya que permiten atacar a una unidad propia o curar a una unidad enemiga. por lo que, para arreglar esto, el Tactician no hará uso del metodo de combate directamente, ahora las unidades tienen un método useItemOn que desambiguará si la unidad es enemiga o no y veráa si activa el combate dependiendo de eso.

Además ahora si una unidad muere en combate, está le enviará un mensaje al tactician para ser borrada de entre sus unidades y tambien se borrará del mapa. Existe el caso especial del Hero si un Hero Muere será un Game Over inmediato para el tactician.

NullUnit (Null pattern)

Este tipo de unidad se creo para efectos de cuando se intenta crear una unidad en una celda no valida (ya existe una unidad en la celda o la celda está fuera del mapa) el factory (que se explicará más adelante) es el que se encarga de decidir si la unidad es valida o no, además un tactician no puede guardar NullUnit's entre sus unidades.

Este tipo de unidad tienen HP=-1, movement=-1, maxItems=0 y location=InvalidLocation. como parametros, además los metodos conflictivos (guardar, dar, equipar items y combatir) se encuentran vacios.

Mapa

Como el mapa se crea desde el GameController y depende de la seed de este se definieron sus constructores: el que no recibe parametros y el que si, este recibe el tamaño del mapa y una seed y crea un mapa cuadrado a partir de esta.

Factories

Hay dos tipos de factories:

  1. Unit Factory: Hay 9 de estas (Los sorcerer son un caso especial por lo que se prefirió dejarlos en 3 factories distintos) donde cada factory permite retornar una unidad estandar tanto con un item (correspondiente) equipado o no (1 método para c/ acción) si la posicion de la unidad que se quiere crear no es valido se retornará una NullUnit como se explica más arriba.
  2. Item Factory: Hay 8 de estos y simplemente retornan un item estandar.

Ejecución

En esta versión la ejecución sigue siendo por medio los test, (escribí un script que corría el juego por el command line de intellij pero no lo coloqué en la repo porque era feito, aunque funcional).

Principalmente los test del GameController se colocan en distintos casos de acuerdo a lo que puede ocurrir en un juego, en el caso del Tactician el testeo es para nada extenso (para nada) ya que el GameController al funcionar como su adapter hace uso de todos los métodos del tactician y si el GC funciona bien, el tactician tambien. Los factories tampoco fueron testeados más que su uso dado en el teste del gamecontroller.

Alpaca_Emblem 1.5

El proyecto se encuentra en su versión 1.5 acorde a los requisitos de la entrega n°1.

En las secciones Unidades e Items se explicán algunas implementaciones, extensiones que se le hicieron al código dado, la visibilidad de parametros, etc. En Equipamiento e intercambio de items y Combate se explica en especifico los requerimientos puros y duros de la entrega.

Unidades:

Las unidades son objetos de una clase que extiende a la clase abstracta AbstractUnit que a su vez implementa a la interfaz IUnit.

  • Cada unidad tiene los siguientes atributos privados en la clase abstracta:

    1. Hitpoints: currentHitPoints es un double y representa la vida actual de una unidad y maxHitpoints es un final int y representa la cantidad máxima de vida de una unidad.
    2. Movement: movement es un _ final int_ que represena la cantidad maxima de celdas que una unidad se puede mover.
    3. Location: location es un objeto de la clase Location y representa la locación actual de un personaje.
    4. Items: los items son objetos de la "clase" IEquipableItem (se explicará mas tarde) maxItems es un final int que representa la cantidad maxima de items que una unidad puede portar, items es una ArrayList de los items que la unidad porta y equipedItem es el item que la unidad tiene equipado.
  • El juego cuenta con 7 Unidades:

    1. Archer: Solo puede equiparse Bow's.
    2. Fighter: Solo puede equiparse Axe's.
    3. Sword Master: Solo puede equiparse Sword's.
    4. Alpaca: Puede portar una cantidad ilimitada de items pero equiparse ninguno.
    5. Cleric: Solo puede equiparse Staff's y no puede atacar.
    6. Hero: Solo puede equiparse Spear's.
    7. Sorcerer: Solo puede equiparse LightBooks's, DarknessBooks's y AnimaBooks's.

A excepción de la Alpaca cada unidad pude portar como máximo 3 items y de estos y de estos 3 items solo puede equiparse 1.

Items:

Los items son objetos de una clase que (dependiendo de si es un item magico o no) extiende a la clase abstracta AbstractMagicItem o AbstractNonMagicItem, estas extienden a la clase abstracta AbstractItem que a su vez implementa a la interfaz IEquipableItem.

  • Cada item tiene los siguientes atributos privados:

    1. Nombre: name es un final String y es el nombre del item.
    2. Poder: power es un final int y representa el poder del item, pregunta ¿Por qué los puntos de vida de las unidades son double cuanto el poder de los items son final int? el efecto que producen las armas se puede ver potenciado o disminuido bajo ciertas condiciones que se verán más adelante en las secciones Fortalezas y Debilidades y Combate.
    3. Dueño: owner es efectivamente la unidad que tiene equipado el item.
  • Cada item tiene los siguientes atributos protegidos:

    1. Rango mínimo: minRange es un int que representa la cantidad mínima de celdas que tiene que estar un adversario para ser atacado por la unidad que equipa el item. Por defecto es 1, en casos especiales como el Bow este es 2.-
    2. Rango máximo: maxRange es un int que representa la cantidad máxima de celdas que tiene que estar un adversario para ser atacado por la unidad que equipa el item. tiene que ser estrictamente mayor a minRange.
  • Existen dos clases de items, mágicos y no mágicos y su comportamiento se diferencia principalmente al momento de un combate, esto se explicará en la sección Fortalezas y Debilidades.

    • Items Mágicos: Son principalmente los libros
    1. Libros de Luz: LightBook
    2. Libros de Oscuridad: DarknessBook
    3. Libros de Ánimas: AnimaBook
    • Items no Mágicos:
    1. Hacha: Axe
    2. Arco: Bow (tiene rango minimo 2)
    3. Lanza: Spear
    4. Bastón: Staff (no ataca, cura)
    5. Espada: Sword

Fortalezas y Debilidades

Algunos items son fuertes y/o debiles contra otros, que sean fuertes implica que cada vez que hacen daño a una unidad esta se potencia por un factor de 1.5 y si son débiles el daño disminuye en 20 o en su defecto se reduce a 0. Los items mágicos son fuertes contra los items no mágicos y a su vez, los items no mágicos son fuertes contra los items mágicos, por lo que cada vez que se ataquen una a la otra el da{o se verá potenciadoen un factor de 1.5.

Entre items de la misma clase tambien hay fortalezas y débilidades y se verán en la siguientes tablas:

Item Débil contra Fuerte contra
Hacha Espada Lanza
Espada Lanza Hacha
Lanza Hacha Espada
Item Débil contra Fuerte contra
Ánima Oscuridad Luz
Oscuridad Luz Ánima
Luz Ánima Oscuridad

Mapa

No se hicieron cambios en la implementación de mapa.

Equipamiento e intercambio de items

Para poder equipar un item a una unidad se tienen que cumplir como condición: la unidad porta el item en su lista de items y el item debe ser del tipo apto para la unidad. Para implemantar esto se utilizó la estrategia de Double Dispatch, la unidad no sabe que items puede equiparse, el item lo decidirá por él. Por ejemplo tenemos una unidad unit si hacemos equipItem(item) se enviará un mensaje al item, este item sabrá que hacer para cada tipo de unidad, si unit e item son compatibles item se asignará como owner a unit y unit asignará a item como equippedItem por el contrario, si item no tiene instrucciones para equiparse a unit no será equipado.

Para el intercambio basta una estrategia simple. Tenemos dos unidades unit1 y unit2 si unit1 quiere darle un item a unit2 se tienen que cumplir tres condiciones: la distacia entre unit1 y unit2 debe ser igual a 1, unit1 debe poseer el item y unit2 debe tener como máximo maxItems-1 items. Como caso extra si unit1 tiene equipado el item este cambiara su owner a null y tambien se desequipará de unit2 para luego seguir la vía usual del intercambio, que sería eliminar el item de la lista de items de unit1 y agregarlo en la lista de unit2.

Combate

Para el combate también se utilizó la estrategia de Dual Dispatch. La unidad abstracta cuenta con un método combat(IUnit unit). Sea unit1 y unit2 dos tipos de unidades. Primero se verifican para unit1 ciertas condiciones, ataca si puede, luego unit2 verifica si tambien se cumple las condiciones y atacará de vuelta.

Las condiciones son: la unidad que ataca debe tener sus currentHitpoints distintos de 0 (es imposible tener menos que cero), la unidad debe tener un item equipado y la unidad adversaria debe estar en el rango del item de la unidad que ataca. Si en alguna parte del combate no se cumplen las condiciones, el combate termina.

Ahora ¿Cómo se combate? Después de verificar que las condiciones previamente mencionadas se cumplan para unit1 se envia un mensaje al item equipado de unit1 (item1) diciendole que atacará a unit2, como ya se sabe que unit2 está en el rango item1 enviará un mensaje al item de unit2 (item2) diciendole que está siendo atacado por un arma del tipo que de item1, así item2 sabrá como reaccionar al ataque y dirá cuanto daño debe recibir unit2 ,dependiendo de las fortalezas o debilidades de item2, si el daño neto es menor que 0 se actualiza el daño como 0, item2 envíará un mensaje a unit2 con el daño a asginar y se reducirán los currentsPoints de unit2, si los currentPoints quedan negativos se le asigna 0. Luego se verifican las condiciones para que unit2 pueda atacar a unit1 y devuelve con otro ataque de ser posible finalizando el combate. La implementación funciona pero es algo redundante, hay implementaciones de contrataque muchos más optimos, por ejemplo: una vez se le dice a item2 que fue atacado por un item de la clase item1, item2 sabrá su tipo y el del item atacante y sabrá cuanto daño hará el contrataque y si se cumplen las condiciones de combate item2 mandará un mensaje a unit1 con el daño que recibirá, así mismo para unit2. ¿Porqué no se cambió todo para usar esta implementación? Porque la implementación funciona y no afecta tanto el diseño y aparte el coverage de testeo disminuiría considerablemente ya que el combate implementado funciona de forma simetrica.

Faltó mencionar que pasa con Cleric ya que este no ataca y según se explica en la implementación este debería recibir un contraatque de todos modos, bueno el metodo de combat( ) de Cleric es distinto, si Cleric tiene equipado un item (el Staff), la otra unidad está en rango del Staff y además los currentHitPoints de la unidad son mayores a 0, Cleric le envará un mensaje a su Staff y este a su vez le enviará un mensaje a la unidad que se quiere sanar y se aumentarán sus currentPoints, si los nuevos currentsHitpoints superan a maxHitpoints se asignará como currentHitpoints maxHitpoints para evitar el overHealing.

Ejecución

Como el programa sigue en una versión "primitiva" la ejecución se basa en los test qu se encuentran en la capeta test:

Para el testeo de las unidades se setearon un set de unidades "target" y dos sets de items, uno para equiparlos a las unidades que se querian testear y el otro para equipar a las "target". Entre los test se incluyen el correcto funconamiento de los constructores, la correcta equipación de los items, el funcionamiento del intercambio, la cantidad maxima de items, el movimiento de las unidades, el combate y el correcto funconamiento a la hora de sanar una unidad (testCleric verifica los resultados al sanar a otras unidades).

El testeo del combate es el más "complicado" dado que cada unidad evalua ambitos distintos del comportamiento entre las unidades. testSorcerer evalua como se comportan las unidades al combatir libros con libros o libros contra items no mágicos, testHero, testSwordMaster y testFighter evaluan los resultados al combatir entre ellos. testArcher verifica los resultados de combatir con items magicos o no magicos de corto alcance (spear,axe, sword) y que pasa si el poder del arma es mayor que la vida de la unidad atacada o si la unidad atacada está fuera del rango de su arma, testAlpaca ve que pasa cuando la unidad atacada no tiene item equipado (en este caso la unidad atacada es la ALpaca).

Entre los testeos de los items se encontraba el correcto funcionamiento del constructor, el equipamiento a unidades y tambien como para las unidades el correcto funcionamiento de la curación y los ataques a unidades.

alpaca_emblem's People

Contributors

sebaaaguilera avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.