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.
Desafio
FácilVamos 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 valoresPHYSICAL,MAGICALeRANGED. Adicione um campo privadodescription(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étodosattack(Character target)que retorna uma String descrevendo o ataque, egetDamageType()que retorna um DamageType.Healable.java: Crie uma interface para habilidades de restauração. Declare um métodoheal(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 paraname(String),health(int),maxHealth(int) elevel(int). O construtor recebe name, maxHealth e level, definindo health igual a maxHealth inicialmente. Inclua getters para todos os campos. Adicione um método protegidosetHealth(int health)que garante que a saúde permaneça entre 0 e maxHealth. Crie um métodotakeDamage(int damage)que reduz a saúde e retorna"[name] takes [damage] damage! Health: [health]/[maxHealth]". Adicione um métodoisAlive()retornando true se a saúde for maior que 0. Declare um método abstratogetCharacterClass()retornando uma String.Warrior.java: Crie uma classe que estende Character e implementa Attackable. Adicione um campo privadostrength(int). O construtor recebe name, maxHealth, level e strength. ImplementegetCharacterClass()para retornar"Warrior". ImplementegetDamageType()para retornarPHYSICAL. Implementeattack(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 privadosintelligence(int) emana(int). O construtor recebe name, maxHealth, level, intelligence e mana. ImplementegetCharacterClass()para retornar"Mage". ImplementegetDamageType()para retornarMAGICAL. Implementeattack(Character target)para causar dano igual a intelligence vezes 2, seguindo o mesmo formato do Warrior. Implementeheal(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:strengthCREATE_MAGE:name:maxHealth:level:intelligence:manaATTACK:attackerName:targetNameHEAL:mageName:amountSTATUS: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 healse 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 - AliveEste 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
}
}
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
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy14Desafios Finais
Plataforma de E-LearningSistema BancárioDesenvolvimento de Personagens de JogosServiço de Aluguel de Veículos3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator