Menu
Coddy logo textTech

Desenvolvimento de Personagens de Jogos

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 86 de 87.

Este desafio fará você construir um sistema de Desenvolvimento de Personagens de Jogo que demonstra o poder da POO na modelagem de entidades complexas e interativas.

Projete uma hierarquia de personagens onde uma classe base Character define atributos comuns como vida, nome e nível. Classes especializadas como Warrior, Mage e Archer estendem esta base com habilidades únicas e estilos de combate.

Interfaces funcionam naturalmente aqui: Attackable poderia definir métodos de combate, enquanto Healable lida com habilidades de restauração. Um Mage pode implementar ambos, enquanto um Warrior foca apenas em atacar.

Considere usar o padrão Strategy para diferentes comportamentos de ataque, permitindo que os personagens alternem estilos de combate dinamicamente. O padrão State poderia gerenciar condições do personagem, como os estados normal, envenenado ou atordoado, que afetam o comportamento.

Pense em composição para sistemas de equipamentos onde personagens "têm" armas e armaduras em vez de herdar delas. Use enums para classes de personagens ou tipos de dano, e aplique encapsulamento para proteger os atributos de modificações inválidas.

challenge icon

Desafio

Fácil

Vamos construir um sistema de Desenvolvimento de Personagens de Jogo que demonstra o poder da POO na modelagem de entidades de jogo complexas e interativas! Você criará uma hierarquia de personagens com diferentes estilos de combate, habilidades especiais e um sistema de estado que afeta o comportamento dos personagens.

Você organizará seu código em sete arquivos:

  • DamageType.java: Crie um enum representando diferentes tipos de dano no jogo. Inclua os valores PHYSICAL, MAGICAL e RANGED. Adicione um campo privado description (String), um construtor que o define e um getter. O dano físico deve ter a descrição "brute force", o mágico deve ter "arcane energy" e o de longo alcance deve ter "precision strike".
  • Attackable.java: Crie uma interface definindo capacidades de combate. Declare os métodos attack(Character target) que retorna uma String descrevendo o ataque, e getDamageType() que retorna um DamageType.
  • Healable.java: Crie uma interface para habilidades de restauração. Declare um método heal(int amount) que retorna uma String descrevendo a ação de cura.
  • Character.java: Crie uma classe base abstrata para todos os personagens do jogo. Inclua campos privados para name (String), health (int), maxHealth (int) e level (int). O construtor recebe name, maxHealth e level, definindo health igual a maxHealth inicialmente. Inclua getters para todos os campos. Adicione um método protegido setHealth(int health) que garante que a saúde permaneça entre 0 e maxHealth. Crie um método takeDamage(int damage) que reduz a saúde e retorna "[name] takes [damage] damage! Health: [health]/[maxHealth]". Adicione um método isAlive() retornando true se a saúde for maior que 0. Declare um método abstrato getCharacterClass() retornando uma String.
  • Warrior.java: Crie uma classe que estende Character e implementa Attackable. Adicione um campo privado strength (int). O construtor recebe name, maxHealth, level e strength. Implemente getCharacterClass() para retornar "Warrior". Implemente getDamageType() para retornar PHYSICAL. Implemente attack(Character target) para causar dano igual a strength mais level, chame o método takeDamage do alvo e retorne "[name] strikes with [damageType description] for [damage] damage!" seguido por uma nova linha e o resultado de takeDamage.
  • Mage.java: Crie uma classe que estende Character e implementa tanto Attackable quanto Healable. Adicione campos privados intelligence (int) e mana (int). O construtor recebe name, maxHealth, level, intelligence e mana. Implemente getCharacterClass() para retornar "Mage". Implemente getDamageType() para retornar MAGICAL. Implemente attack(Character target) para causar dano igual a intelligence vezes 2, seguindo o mesmo formato do Warrior. Implemente heal(int amount) para restaurar a saúde (usando setHealth) e retornar "[name] channels healing magic! Health: [health]/[maxHealth]".
  • Main.java: Dê vida ao seu sistema de jogo! Você receberá uma string de comandos separada por vírgulas:
    • CREATE_WARRIOR:name:maxHealth:level:strength
    • CREATE_MAGE:name:maxHealth:level:intelligence:mana
    • ATTACK:attackerName:targetName
    • HEAL:mageName:amount
    • STATUS:characterName

    Mantenha uma coleção de personagens. Processe cada comando e imprima:

    • CREATE_WARRIOR/CREATE_MAGE: [name] the [characterClass] joins the battle!
    • ATTACK: Imprima o resultado do ataque (a String retornada pelo método attack)
    • HEAL: Imprima o resultado da cura, ou [name] cannot heal se o personagem não for um Mage
    • STATUS: [name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]

    Após todos os comandos, imprima --- Battle Summary --- seguido pelo status de cada personagem.

Você receberá uma entrada: a string de comando separada por vírgulas.

Por exemplo, com a entrada CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf, sua saída seria:

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 desafio combina herança (hierarquia Character), implementação de múltiplas interfaces (Mage implementa tanto Attackable quanto Healable), enums com métodos (DamageType), polimorfismo (tratando diferentes tipos de personagens de forma uniforme) e encapsulamento (gerenciamento de saúde protegido) em um sistema de jogo envolvente!

Folha de consulta

A programação orientada a objetos (POO) permite modelar sistemas complexos por meio de classes, herança, interfaces e padrões de projeto.

Hierarquia de Classes

Crie uma classe base com atributos comuns e estenda-a com classes 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 comportamentos específicos que as classes podem implementar:

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

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

Enums com Campos

Enums podem ter campos, construtores e 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;
    }
}

Implementação de Múltiplas Interfaces

Uma classe pode implementar múltiplas interfaces:

public class Mage extends Character implements Attackable, Healable {
    private int intelligence;
    private int mana;
    
    @Override
    public String attack(Character target) {
        // Implementação
    }
    
    @Override
    public String heal(int amount) {
        // Implementação
    }
}

Encapsulamento

Use campos privados com setters protegidos para controlar o acesso e validar os dados:

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

Polimorfismo

Trate diferentes tipos de personagens de forma uniforme por meio de sua classe base comum ou interfaces, permitindo coleções e chamadas de métodos flexíveis.

Experimente você mesmo

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: Use uma coleção para manter os personagens (LinkedHashMap preserva a ordem de inserção)
        // LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
        
        // TODO: Divida a entrada por vírgula para obter comandos individuais
        // String[] commands = input.split(",");
        
        // TODO: Processe cada comando:
        // - CREATE_WARRIOR:name:maxHealth:level:strength
        //   Imprima: "[name] the Warrior joins the battle!"
        // 
        // - CREATE_MAGE:name:maxHealth:level:intelligence:mana
        //   Imprima: "[name] the Mage joins the battle!"
        // 
        // - ATTACK:attackerName:targetName
        //   Imprima o resultado do ataque a partir do método attack
        // 
        // - HEAL:mageName:amount
        //   Imprima o resultado da cura, ou "[name] cannot heal" se não for um Mage
        // 
        // - STATUS:characterName
        //   Imprima: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
        
        // TODO: Após todos os comandos, imprima "--- Battle Summary ---"
        // Em seguida, imprima o status de cada personagem
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos