Componente de Personagem de Jogo
Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 69 de 70.
Desafio
FácilVamos construir um sistema de personagens de jogo usando o padrão de arquitetura baseada em componentes! Em vez de criar hierarquias de herança rígidas, você comporá personagens anexando componentes independentes que lidam com comportamentos específicos - uma abordagem flexível amplamente utilizada no desenvolvimento de jogos.
Você organizará seu código em cinco arquivos:
IComponent.cs: Defina uma interfaceIComponentno namespaceGame.Components. Todo componente deve ter um métodoUpdate()que imprime o que o componente está fazendo.HealthComponent.cs: Crie uma classeHealthComponentque implementaIComponent. Ela deve rastrear os pontos de vida atuais e máximos, com métodos paraTakeDamage(int amount)eHeal(int amount). A vida nunca deve ficar abaixo de 0 ou acima do máximo. Inclua umevent Action<int> HealthChangedque é disparado sempre que a vida muda, passando o novo valor de vida. O métodoUpdate()deve imprimir o status atual da vida.InventoryComponent.cs: Crie uma classeInventoryComponentque implementaIComponent. Ela gerencia uma lista de nomes de itens com os métodosAddItem(string item)eRemoveItem(string item)(retorna umboolindicando sucesso). O métodoUpdate()deve imprimir o conteúdo do inventário.Character.cs: Crie uma classeCharacterno namespaceGameque contém uma coleção de componentes. Seu personagem precisa de uma propriedadeNamee destes métodos:AddComponent(IComponent component)- anexa um componente ao personagemGetComponent<T>()onde T : IComponent - retorna o primeiro componente do tipo T, ou null se não for encontradoUpdateAll()- chamaUpdate()em cada componente anexado
Program.cs: Reúna tudo criando um personagem, anexando componentes e processando comandos.
Você receberá as seguintes entradas:
- Nome do personagem
- Vida máxima inicial para o HealthComponent
- Número de comandos a serem processados
- Para cada comando: a ação seguida pelos dados relevantes
Formatos de comando:
damage
{amount}
heal
{amount}
add_item
{itemName}
remove_item
{itemName}
updateFormatos de saída:
- Quando a vida muda (via evento):
Health changed: {newHealth} - Ao adicionar um item:
Added: {itemName} - Ao remover um item:
Removed: {itemName}ouItem not found: {itemName} Update()do HealthComponent:Health: {current}/{max}Update()do InventoryComponent:Inventory: {item1}, {item2}, ...ouInventory: empty
Por exemplo, se as entradas forem:
Hero
100
7
add_item
Sword
add_item
Shield
damage
30
heal
10
remove_item
Potion
remove_item
Sword
updateA saída deve ser:
Added: Sword
Added: Shield
Health changed: 70
Health changed: 80
Item not found: Potion
Removed: Sword
Health: 80/100
Inventory: ShieldObserve como o personagem não herda de nada especial - ele simplesmente contém componentes que fornecem comportamento. O método GetComponent<T>() usa genéricos para recuperação segura de tipos, e os eventos notificam quando a vida muda. Essa abordagem de composição permite que você misture e combine componentes livremente!
Experimente você mesmo
using System;
using Game;
using Game.Components;
class Program
{
public static void Main(string[] args)
{
// Lê o nome do personagem
string characterName = Console.ReadLine();
// Lê a vida máxima inicial
int maxHealth = Convert.ToInt32(Console.ReadLine());
// Lê o número de comandos
int numCommands = Convert.ToInt32(Console.ReadLine());
// TODO: Criar um Character com o nome fornecido
// TODO: Criar HealthComponent com maxHealth e InventoryComponent
// TODO: Inscrever-se no evento HealthChanged para imprimir: Health changed: {newHealth}
// TODO: Adicionar ambos os componentes ao personagem
// TODO: Processar cada comando
for (int i = 0; i < numCommands; i++)
{
string command = Console.ReadLine();
// TODO: Lidar com cada tipo de comando:
// - "damage": ler a quantidade, chamar TakeDamage no componente de saúde
// - "heal": ler a quantidade, chamar Heal no componente de saúde
// - "add_item": ler o nome do item, chamar AddItem no componente de inventário
// - "remove_item": ler o nome do item, chamar RemoveItem no componente de inventário
// - "update": chamar UpdateAll no personagem
}
}
}
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy13Desafios Finais
Plataforma de E-learningComponente de Personagem de JogoServiço de Aluguel de Veículos2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de Métodos