Menu
Coddy logo textTech

Desarrollo de personajes de videojuegos

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 86 de 87.

Este desafío consiste en construir un sistema de Desarrollo de Personajes de Juego que demuestra el poder de la POO al modelar entidades complejas e interactivas.

Diseña una jerarquía de personajes donde una clase base Character defina atributos comunes como salud, nombre y nivel. Clases especializadas como Warrior, Mage y Archer extiendan esta base con habilidades y estilos de combate únicos.

Las interfaces funcionan de forma natural aquí: Attackable podría definir métodos de combate, mientras que Healable maneja habilidades de restauración. Un Mage podría implementar ambos, mientras que un Warrior se enfoca solo en atacar.

Considere utilizar el patrón Strategy para diferentes comportamientos de ataque, lo que permite a los personajes cambiar de estilo de combate de forma dinámica. El patrón State podría gestionar las condiciones del personaje, como los estados normal, envenenado o aturdido, que afectan al comportamiento.

Piense en la composición para sistemas de equipamiento donde los personajes "tienen" armas y armaduras en lugar de heredar de ellas. Use enums para las clases de personajes o los tipos de daño, y aplique el encapsulamiento para proteger las estadísticas de modificaciones no válidas.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de Desarrollo de Personajes de Juego que demuestre el poder de la POO al modelar entidades de juego complejas e interactivas! Crearás una jerarquía de personajes con diferentes estilos de combate, habilidades especiales y un sistema de estado que afecta el comportamiento de los personajes.

Organizarás tu código en siete archivos:

  • DamageType.java: Crea un enum que represente los diferentes tipos de daño en el juego. Incluye los valores PHYSICAL, MAGICAL y RANGED. Agrega un campo privado description (String), un constructor que lo asigne y un getter. El daño físico debe tener la descripción "brute force", el mágico debe tener "arcane energy" y el a distancia debe tener "precision strike".
  • Attackable.java: Crea una interfaz que defina las capacidades de combate. Declara los métodos attack(Character target) que devuelve un String describiendo el ataque, y getDamageType() que devuelve un DamageType.
  • Healable.java: Crea una interfaz para las habilidades de restauración. Declara un método heal(int amount) que devuelve un String describiendo la acción de curación.
  • Character.java: Crea una clase base abstracta para todos los personajes del juego. Incluye campos privados para name (String), health (int), maxHealth (int) y level (int). El constructor recibe name, maxHealth y level, estableciendo la salud igual a maxHealth inicialmente. Incluye getters para todos los campos. Agrega un método protegido setHealth(int health) que asegure que la salud se mantenga entre 0 y maxHealth. Crea un método takeDamage(int damage) que reduzca la salud y devuelva "[name] takes [damage] damage! Health: [health]/[maxHealth]". Agrega un método isAlive() que devuelva true si la salud es mayor que 0. Declara un método abstracto getCharacterClass() que devuelva un String.
  • Warrior.java: Crea una clase que extienda de Character e implemente Attackable. Agrega un campo privado strength (int). El constructor recibe name, maxHealth, level y strength. Implementa getCharacterClass() para que devuelva "Warrior". Implementa getDamageType() para que devuelva PHYSICAL. Implementa attack(Character target) para infligir un daño igual a strength más level, llama al método takeDamage del objetivo y devuelve "[name] strikes with [damageType description] for [damage] damage!" seguido de un salto de línea y el resultado de takeDamage.
  • Mage.java: Crea una clase que extienda de Character e implemente tanto Attackable como Healable. Agrega campos privados intelligence (int) y mana (int). El constructor recibe name, maxHealth, level, intelligence y mana. Implementa getCharacterClass() para que devuelva "Mage". Implementa getDamageType() para que devuelva MAGICAL. Implementa attack(Character target) para infligir un daño igual a intelligence multiplicado por 2, siguiendo el mismo formato que Warrior. Implementa heal(int amount) para restaurar la salud (usando setHealth) y devuelve "[name] channels healing magic! Health: [health]/[maxHealth]".
  • Main.java: ¡Dale vida a tu sistema de juego! Recibirás una cadena de comandos separados por comas:
    • CREATE_WARRIOR:name:maxHealth:level:strength
    • CREATE_MAGE:name:maxHealth:level:intelligence:mana
    • ATTACK:attackerName:targetName
    • HEAL:mageName:amount
    • STATUS:characterName

    Mantén una colección de personajes. Procesa cada comando e imprime:

    • CREATE_WARRIOR/CREATE_MAGE: [name] the [characterClass] joins the battle!
    • ATTACK: Imprime el resultado del ataque (el String devuelto por el método attack)
    • HEAL: Imprime el resultado de la curación, o [name] cannot heal si el personaje no es un Mage
    • STATUS: [name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]

    Después de todos los comandos, imprime --- Battle Summary --- seguido del estado de cada personaje.

Recibirás una entrada: la cadena de comandos separados por comas.

Por ejemplo, con la entrada CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf, tu salida sería:

Thorin the Warrior joins the battle!
Gandalf the Mage joins the battle!
Thorin strikes with brute force for 20 damage!
Gandalf takes 20 damage! Health: 60/80
Gandalf channels healing magic! Health: 80/80
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive
--- Battle Summary ---
Thorin (Warrior) - Level 5 - Health: 100/100 - Alive
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive

¡Este desafío combina herencia (jerarquía Character), implementación de múltiples interfaces (Mage implementa tanto Attackable como Healable), enums con métodos (DamageType), polimorfismo (tratar diferentes tipos de personajes de manera uniforme) y encapsulamiento (gestión protegida de la salud) en un sistema de juego atractivo!

Hoja de referencia

La programación orientada a objetos (POO) permite modelar sistemas complejos a través de clases, herencia, interfaces y patrones de diseño.

Jerarquía de clases

Cree una clase base con atributos comunes y extiéndala con clases especializadas:

public abstract class Character {
    private String name;
    private int health;
    private int maxHealth;
    private int level;
    
    public Character(String name, int maxHealth, int level) {
        this.name = name;
        this.maxHealth = maxHealth;
        this.health = maxHealth;
        this.level = level;
    }
    
    protected void setHealth(int health) {
        this.health = Math.max(0, Math.min(health, maxHealth));
    }
    
    public abstract String getCharacterClass();
}

Interfaces

Defina contratos para comportamientos específicos que las clases pueden implementar:

public interface Attackable {
    String attack(Character target);
    DamageType getDamageType();
}

public interface Healable {
    String heal(int amount);
}

Enums con campos

Los enums pueden tener campos, constructores y métodos:

public enum DamageType {
    PHYSICAL("brute force"),
    MAGICAL("arcane energy"),
    RANGED("precision strike");
    
    private String description;
    
    private DamageType(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

Implementación de múltiples interfaces

Una clase puede implementar múltiples interfaces:

public class Mage extends Character implements Attackable, Healable {
    private int intelligence;
    private int mana;
    
    @Override
    public String attack(Character target) {
        // Implementación
    }
    
    @Override
    public String heal(int amount) {
        // Implementación
    }
}

Encapsulamiento

Use campos privados con setters protegidos para controlar el acceso y validar los datos:

protected void setHealth(int health) {
    this.health = Math.max(0, Math.min(health, maxHealth));
}

Polimorfismo

Trate diferentes tipos de personajes de manera uniforme a través de su clase base común o interfaces, permitiendo colecciones y llamadas a métodos flexibles.

Pruébalo tú mismo

import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Usa una colección para mantener los personajes (LinkedHashMap preserva el orden de inserción)
        // LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
        
        // TODO: Divide la entrada por comas para obtener comandos individuales
        // String[] commands = input.split(",");
        
        // TODO: Procesa cada comando:
        // - CREATE_WARRIOR:name:maxHealth:level:strength
        //   Imprime: "[name] the Warrior joins the battle!"
        // 
        // - CREATE_MAGE:name:maxHealth:level:intelligence:mana
        //   Imprime: "[name] the Mage joins the battle!"
        // 
        // - ATTACK:attackerName:targetName
        //   Imprime el resultado del ataque desde el método attack
        // 
        // - HEAL:mageName:amount
        //   Imprime el resultado de la curación, o "[name] cannot heal" si no es un Mage
        // 
        // - STATUS:characterName
        //   Imprime: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
        
        // TODO: Después de todos los comandos, imprime "--- Battle Summary ---"
        // Luego imprime el estado de cada personaje
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos