Sistema de Personagens de Jogos
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 107 de 107.
Desafio
FácilVamos construir um Sistema de Personagens de Jogo que reúne incorporação de structs, interfaces e o padrão Strategy para criar mecânicas de combate flexíveis! Você projetará diferentes tipos de personagens que podem atacar e defender de maneiras únicas, com habilidades que podem ser trocadas em tempo de execução.
Você organizará seu código em cinco arquivos:
character.go: Defina uma structCharacterbase com campos comuns:Name(string),Health(int) eMaxHealth(int). Inclua um construtorNewCharactere os métodos:IsAlive() bool: retorna true se a vida for maior que 0Status() string: retorna o formato:[Name]: [Health]/[MaxHealth] HP
interfaces.go: Defina as interfaces de combate que permitem o polimorfismo:- Interface
AttackercomAttack() int: retorna o dano causado - Interface
DefendercomTakeDamage(damage int) int: aplica a redução de dano e retorna o dano efetivamente recebido - Interface
AbilitycomUse() string: retorna uma descrição do efeito da habilidade
- Interface
characters.go: Crie três tipos de personagens que incorporemCharactere implementem tantoAttackerquantoDefender:Warrior: possui um campoStrength(int) e um campoArmor(int). O ataque retorna Strength como dano. TakeDamage reduz o dano recebido por Armor (com no mínimo 1 de dano recebido).Mage: possui os camposIntelligence(int) eMagicResist(int). O ataque retorna Intelligence * 2 como dano. TakeDamage reduz o dano recebido por MagicResist / 2 (com no mínimo 1 de dano recebido).Archer: possui os camposAgility(int) eEvasion(int). O ataque retorna Agility + 5 como dano. TakeDamage: se Evasion > 10, reduz o dano em 25% (divisão inteira); caso contrário, recebe o dano total (com no mínimo 1 de dano recebido).Inclua construtores para cada um:
NewWarrior,NewMage,NewArcher, que recebem nome, vida e os valores de atributos específicos.abilities.go: Implemente o padrão Strategy com habilidades que podem ser trocadas:Struct
FireSpellcomPower(int). SeuUse()retorna:Casts fireball for [Power] damageStruct
IceSpellcomPower(int). SeuUse()retorna:Casts ice shard for [Power] damageStruct
PowerStrikecomMultiplier(int). SeuUse()retorna:Performs power strike at [Multiplier]x damageAdicione um campo
ability(do tipoAbility) à struct Mage, com os métodosSetAbility(a Ability)eUseAbility() string. UseAbility retornaNo ability setse ability for nil.main.go: Crie personagens e demonstre as mecânicas de combate.Leia o tipo de personagem (
warrior,mageouarcher), depois leia o nome, a vida e os atributos específicos do tipo. Crie o personagem apropriado.Em seguida, leia o número de ações. Cada ação é uma destas:
status: exiba o status do personagemattack: exiba[Name] attacks for [damage] damagedefend [amount]: aplique o dano e exiba[Name] takes [actual] damagesetability [type] [power]: somente para magos, defina a habilidade (type éfire,iceoustrike)useability: somente para magos, exiba o resultado de Use() da habilidade
As seguintes entradas serão fornecidas:
- Tipo de personagem, nome, vida e atributos específicos do tipo
- Número de ações, depois cada ação em uma linha separada
Por exemplo, dadas as entradas:
warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100Sua saída deverá ser:
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damageE dadas as entradas:
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40Sua saída deverá ser:
Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damageE dadas as entradas:
archer
Legolas
90
18
15
4
status
attack
defend 24
statusSua saída deverá ser:
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HPObserve como a incorporação de structs permite que cada tipo de personagem compartilhe os campos e métodos da Character base, enquanto as interfaces possibilitam o combate polimórfico, no qual qualquer Attacker pode causar dano e qualquer Defender pode recebê-lo. O padrão Strategy se destaca com as habilidades intercambiáveis do Mage: o mesmo personagem pode usar diferentes feitiços sem alterar sua implementação principal!
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Ler o tipo do personagem
scanner.Scan()
charType := strings.TrimSpace(scanner.Text())
// Ler o nome do personagem
scanner.Scan()
name := strings.TrimSpace(scanner.Text())
// Ler a vida
scanner.Scan()
health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Ler o primeiro atributo específico do tipo
scanner.Scan()
stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Ler o segundo atributo específico do tipo
scanner.Scan()
stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// TODO: Crie o personagem apropriado com base em charType
// Use as variáveis: charType, name, health, stat1, stat2
// Para warrior: stat1 = Strength, stat2 = Armor
// Para mage: stat1 = Intelligence, stat2 = MagicResist
// Para archer: stat1 = Agility, stat2 = Evasion
// Ler o número de ações
scanner.Scan()
numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Processar cada ação
for i := 0; i < numActions; i++ {
scanner.Scan()
line := strings.TrimSpace(scanner.Text())
parts := strings.Fields(line)
action := parts[0]
// TODO: Trate cada tipo de ação:
// - "status": imprima o Status() do personagem
// - "attack": imprima "[Name] attacks for [damage] damage"
// - "defend [amount]": aplique o dano e imprima "[Name] takes [actual] damage"
// - "setability [type] [power]": para magos, defina a habilidade (fire, ice ou strike)
// - "useability": para magos, imprima o resultado de UseAbility()
_ = action // Remova esta linha ao implementar
_ = fmt.Println // Remova esta linha ao implementar
}
}
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online