Menu
Coddy logo textTech

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.

challenge icon

Desafio

Fácil

Vamos 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 struct Character base com campos comuns: Name (string), Health (int) e MaxHealth (int). Inclua um construtor NewCharacter e os métodos:
    • IsAlive() bool: retorna true se a vida 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 efetivamente recebido
    • Interface Ability com Use() string: retorna uma descrição do efeito da habilidade
  • characters.go: Crie três tipos de personagens que incorporem Character e implementem tanto Attacker quanto Defender:

    Warrior: possui um campo Strength (int) e um campo Armor (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 campos Intelligence (int) e MagicResist (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 campos Agility (int) e Evasion (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 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 ability 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, 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 personagem
    • attack: exiba [Name] attacks for [damage] damage
    • defend [amount]: aplique o dano e exiba [Name] takes [actual] damage
    • setability [type] [power]: somente para magos, defina a habilidade (type é fire, ice ou strike)
    • 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 100

Sua saída deverá ser:

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

E dadas as entradas:

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

Sua 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 damage

E dadas as entradas:

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Sua saída deverá 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 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

Pratique por conta própria: Compilador de Go online