Menu
Coddy logo textTech

Sistema de Personagens de Jogo

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 107 de 107.

challenge icon

Desafio

Fácil

Vamos construir um Sistema de Personagens de Jogo que reúne incorporação de structs (struct embedding), 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 struct base Character com campos comuns: Name (string), Health (int) e MaxHealth (int). Inclua um construtor NewCharacter e os métodos:
    • IsAlive() bool — retorna true se a saúde for maior que 0
    • Status() string — retorna o formato: [Name]: [Health]/[MaxHealth] HP
  • interfaces.go: Defina as interfaces de combate que permitem o polimorfismo:
    • Interface Attacker com Attack() int — retorna o dano causado
    • Interface Defender com TakeDamage(damage int) int — aplica a redução de dano e retorna o dano real recebido
    • Interface Ability com Use() string — retorna uma descrição do efeito da habilidade
  • characters.go: Crie três tipos de personagens que incorporam Character e implementam tanto Attacker quanto Defender:

    Warrior — possui os campos Strength (int) e Armor (int). Attack retorna Strength como dano. TakeDamage reduz o dano recebido pela Armor (mínimo de 1 de dano recebido).

    Mage — possui os campos Intelligence (int) e MagicResist (int). Attack retorna Intelligence * 2 como dano. TakeDamage reduz o dano recebido por MagicResist / 2 (mínimo de 1 de dano recebido).

    Archer — possui os campos Agility (int) e Evasion (int). Attack retorna Agility + 5 como dano. TakeDamage: se Evasion > 10, reduz o dano em 25% (divisão inteira), caso contrário, recebe o dano total (mínimo de 1 de dano recebido).

    Inclua construtores para cada um: NewWarrior, NewMage, NewArcher que recebam o nome, saúde e seus valores de atributos específicos.

  • abilities.go: Implemente o padrão Strategy com habilidades trocáveis:

    Struct FireSpell com Power (int). Seu Use() retorna: Casts fireball for [Power] damage

    Struct IceSpell com Power (int). Seu Use() retorna: Casts ice shard for [Power] damage

    Struct PowerStrike com Multiplier (int). Seu Use() retorna: Performs power strike at [Multiplier]x damage

    Adicione um campo ability (do tipo Ability) à struct Mage, com os métodos SetAbility(a Ability) e UseAbility() string. UseAbility retorna No ability set se a habilidade for nil.

  • main.go: Crie personagens e demonstre as mecânicas de combate.

    Leia o tipo de personagem (warrior, mage ou archer), depois leia o nome do personagem, saúde e atributos específicos do tipo. Crie o personagem apropriado.

    Em seguida, leia o número de ações. Cada ação é uma das seguintes:

    • status — imprime o status do personagem
    • attack — imprime [Name] attacks for [damage] damage
    • defend [amount] — aplica o dano e imprime [Name] takes [actual] damage
    • setability [type] [power] — apenas para magos, define a habilidade (o tipo é fire, ice ou strike)
    • useability — apenas para magos, imprime o resultado do Use() da habilidade

As seguintes entradas serão fornecidas:

  • Tipo de personagem, nome, saúde e atributos específicos do tipo
  • Número de ações, seguido por cada ação em uma linha separada

Por exemplo, dado:

warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100

Sua saída deve ser:

Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damage

E dado:

mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40

Sua saída deve ser:

Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damage

E dado:

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Sua saída deve ser:

Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HP

Observe como a incorporação de structs permite que cada tipo de personagem compartilhe os campos e métodos base de Character, enquanto as interfaces permitem o combate polimórfico onde qualquer Attacker pode causar dano e qualquer Defender pode recebê-lo. O padrão Strategy brilha com as habilidades trocáveis do Mago — o mesmo personagem pode usar feitiços diferentes 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 de 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: Criar o personagem apropriado com base em charType
	// Usar 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: Lidar com cada tipo de ação:
		// - "status": imprimir o Status() do personagem
		// - "attack": imprimir "[Name] attacks for [damage] damage"
		// - "defend [amount]": aplicar dano e imprimir "[Name] takes [actual] damage"
		// - "setability [type] [power]": para mages, definir habilidade (fire, ice, ou strike)
		// - "useability": para mages, imprimir 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

Pratique por conta própria: Compilador de Go online