Ejercicio Largo: La Batalla por el Trono de Código (Juego de Rol) ⚔️
Resultados de Aprendizaje
Este ejercicio trabaja los siguientes RAs del módulo de Programación:
- RA4 — Aplica de forma integrada todos los principios avanzados de POO: herencia, clases abstractas, interfaces, polimorfismo, composición y colecciones con comparadores.
Ejercicio por fases
Este ejercicio integral está diseñado para poner en práctica todos los conceptos avanzados de la POO de la Unidad 6. Se divide en 8 fases incrementales — completa cada fase antes de pasar a la siguiente.
Fase 1: La Jerarquía de Clases (Herencia y Abstractas)
En nuestro juego de rol, existen diferentes clases de personajes. Todos comparten características, pero cada uno es único.
1.1. Diagrama de Clases Inicial
Tendremos una clase base Personaje y tres especializaciones: Guerrero, Mago y Orco.
classDiagram
class Personaje {
<<abstract>>
# String nombre
# int vida
# int nivel
+ Personaje(nombre, vida, nivel)
+ toString()
+ atacar(Personaje objetivo)*
}
class Guerrero {
- int furia
+ Guerrero(nombre, vida, nivel, furia)
}
class Mago {
- int mana
+ Mago(nombre, vida, nivel, mana)
}
class Orco {
- int rabia
+ Orco(nombre, vida, nivel, rabia)
}
Personaje <|-- Guerrero
Personaje <|-- Mago
Personaje <|-- Orco
1.2. Tareas
- Crea un nuevo proyecto llamado
JuegoDeRol. - Crea un paquete
modelpara las clases del dominio y un paquetemainpara el programa principal. - Implementa la clase Abstracta
Personaje.- ¿Por qué abstracta? Porque no queremos crear un "Personaje" genérico.
- Añade un constructor que reciba
nombre,vidaynivel. - Define el método abstracto
atacar(Personaje objetivo). - Sobrescribe
toString()para mostrar los datos básicos.
- Implementa las clases hijas
Guerrero,MagoyOrco.- Guerrero: Tiene atributo extra
furia. - Mago: Tiene atributo extra
mana. - Orco: Tiene atributo extra
rabia. - Deben tener un constructor que invoque al constructor del padre usando
super(...). - Implementa el método
atacar()de forma sencilla (por ahora solo unSystem.out.printlnindicando quién ataca a quién).
- Guerrero: Tiene atributo extra
Fase 2: Atributos y Estado (Encapsulamiento)
Vamos a dar vida a las estadísticas de los personajes.
2.1. Nuevos Atributos en Personaje
Además de lo básico, añade:
agilidad(int): Determinará quién ataca primero.resistencia(int): Reducirá el daño recibido.
2.2. Tareas
- Actualiza el constructor de
Personaje(y de los hijos) para incluiragilidadyresistencia. - Actualiza el
toString()para mostrar todas las estadísticas:"Conan (Guerrero) | Nivel: 5 | Vida: 100 | Furia: 50 | Agilidad: 10 | Resistencia: 5"
Fase 3: El Contrato de Combate (Interfaces)
Queremos que nuestros personajes puedan recibir daño de forma estandarizada.
3.1. La Interfaz Atacable
Crea una interfaz en el paquete model llamada Atacable.
3.2. Implementación
- Haz que la clase abstracta
PersonajeimplementeAtacable. - Implementa los métodos en
Personaje:recibirDano(int dano):- Calcula el daño real:
dano - resistencia. - Si el daño real es menor a 0, se queda en 0 (la armadura absorbió todo).
- Resta el daño real a la
vida. - Muestra por pantalla: "Conan recibe X de daño. Vida restante: Y".
- Calcula el daño real:
estaVivo(): Devuelvetruesi la vida es mayor a 0.
Fase 4: Comportamiento Especializado (Polimorfismo)
Ahora aprovecharemos el Polimorfismo para que cada clase ataque de forma única.
4.1. Reglas de Ataque
Modifica el método atacar(Personaje objetivo) en cada clase:
- Guerrero:
- Daño =
nivel * 2 + furia. - Si tiene menos de 10 de vida, su daño se duplica (¡Berserker!).
- Daño =
- Mago:
- Daño =
nivel * nivel + mana. - Si tiene menos de 10 de
mana, no puede atacar (daño 0) y recupera 5 de maná.
- Daño =
- Orco:
- Daño =
nivel * 3 + rabia. - Siempre ignora la defensa del rival (llama a un método especial o truco, o simplifícalo haciendo que el daño sea directo).
- Daño =
4.2. Prueba Polimórfica
En el main, crea un método void probarCombate():
- Crea un
ArrayList<Personaje>. - Añade un Guerrero, un Mago y un Orco.
- Recorre la lista y haz que todos ataquen al primero de la lista.
- Fíjate cómo Java decide qué método
atacarejecutar en tiempo de ejecución.
- Fíjate cómo Java decide qué método
Fase 5: Equipos y Ordenación (Colecciones y Comparadores)
5.1. Comparación Natural
Haz que Personaje implemente Comparable<Personaje>.
- El orden natural será por Agilidad (de mayor a menor), para decidir quién ataca antes en un turno.
5.2. Métodos de Igualdad
Implementa equals() y hashCode() en Personaje.
- Dos personajes son iguales si tienen el mismo
nombre.
5.3. Clase Gremio (Agrupación)
Crea una clase Gremio que tenga:
nombredel gremio.ArrayList<Personaje>miembros.- Métodos:
reclutar(Personaje p),expulsar(Personaje p),mostrarMiembros(). - En
mostrarMiembros(), usaCollections.sort()para mostrarlos ordenados por agilidad.
Fase 6: Inventario (Composición)
Los personajes llevan una mochila con objetos.
6.1. Clase Item
- Atributos:
nombre,aumentoAtaque(int),aumentoDefensa(int).
6.2. Composición en Personaje
- Añade un atributo
Mochila(oArrayList<Item>) enPersonaje. - Añade métodos
cogerItem(Item i)ygetInventario(). - Importante: Modifica el cálculo de daño (al atacar) y defensa (al recibir daño) para sumar los bonus de los objetos que lleven en la mochila.
Fase 7: El Juego (Programa Principal)
Crea un menú interactivo en el main:
- Alta de Personaje: Pide datos y crea Guerrero/Mago/Orco.
- Crear Gremio: Crea un grupo vacío.
- Gestión de Gremio: Añadir/Echar personajes del gremio.
- Entrenar (Combate):
- Elige dos personajes del gremio.
- Haz que luchen a muerte.
- Muestra un log paso a paso:
- "Turno 1: Conan ataca a Gandalf..."
- "Gandalf recibe 20 daño..."
- Salir.
Fase 8: Diagrama de Clases Final
classDiagram
class Atacable {
<<interface>>
+ recibirDano(int cantidad)
+ estaVivo() boolean
}
class Comparable {
<<interface>>
+ compareTo(Personaje o)
}
class Personaje {
<<abstract>>
# String nombre
# int vida
# int nivel
# int agilidad
# int resistencia
# ArrayList~Item~ mochila
+ atacar(Personaje objetivo)*
+ cogerItem(Item i)
}
class Guerrero {
- int furia
}
class Mago {
- int mana
}
class Orco {
- int rabia
}
class Gremio {
- String nombre
- ArrayList~Personaje~ miembros
}
class Item {
- String nombre
- int aumentoAtaque
- int aumentoDefensa
}
Atacable <|.. Personaje
Comparable <|.. Personaje
Personaje <|-- Guerrero
Personaje <|-- Mago
Personaje <|-- Orco
Gremio o-- Personaje : Agregación
Personaje *-- Item : Composición