Menu
Coddy logo textTech

Sistema dei personaggi di gioco

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 107 di 107.

challenge icon

Sfida

Facile

Costruiamo un sistema di personaggi di gioco che combina l'embedding delle struct, le interfacce e il pattern Strategy per creare meccaniche di combattimento flessibili! Progetterai diversi tipi di personaggi capaci di attaccare e difendersi in modi unici, con abilità che possono essere sostituite durante l'esecuzione.

Organizzerai il codice in cinque file:

  • character.go: definisci una struct di base Character con campi comuni: Name (string), Health (int) e MaxHealth (int). Includi un costruttore NewCharacter e i metodi:
    • IsAlive() bool: restituisce true se la salute è maggiore di 0
    • Status() string: restituisce il formato: [Name]: [Health]/[MaxHealth] HP
  • interfaces.go: definisci le interfacce di combattimento che consentono il polimorfismo:
    • Interfaccia Attacker con Attack() int: restituisce il danno inflitto
    • Interfaccia Defender con TakeDamage(damage int) int: applica la riduzione del danno e restituisce il danno effettivamente subito
    • Interfaccia Ability con Use() string: restituisce una descrizione dell'effetto dell'abilità
  • characters.go: crea tre tipi di personaggi che incorporano Character e implementano sia Attacker sia Defender:

    Warrior: ha i campi Strength (int) e Armor (int). Attack restituisce Strength come danno. TakeDamage riduce il danno in arrivo di Armor (il danno subito è almeno 1).

    Mage: ha i campi Intelligence (int) e MagicResist (int). Attack restituisce Intelligence * 2 come danno. TakeDamage riduce il danno in arrivo di MagicResist / 2 (il danno subito è almeno 1).

    Archer: ha i campi Agility (int) e Evasion (int). Attack restituisce Agility + 5 come danno. TakeDamage: se Evasion > 10, riduce il danno del 25% (divisione intera), altrimenti subisce l'intero danno (il danno subito è almeno 1).

    Includi un costruttore per ciascun tipo: NewWarrior, NewMage, NewArcher, che accettano nome, salute e i valori delle statistiche specifiche.

  • abilities.go: implementa il pattern Strategy con abilità intercambiabili:

    Struct FireSpell con Power (int). Il suo Use() restituisce: Casts fireball for [Power] damage

    Struct IceSpell con Power (int). Il suo Use() restituisce: Casts ice shard for [Power] damage

    Struct PowerStrike con Multiplier (int). Il suo Use() restituisce: Performs power strike at [Multiplier]x damage

    Aggiungi un campo ability (di tipo Ability) alla struct Mage, con i metodi SetAbility(a Ability) e UseAbility() string. UseAbility restituisce No ability set se ability è nil.

  • main.go: crea personaggi e mostra le meccaniche di combattimento.

    Leggi il tipo di personaggio (warrior, mage o archer), poi leggi il nome del personaggio, la salute e le statistiche specifiche del tipo. Crea il personaggio appropriato.

    Quindi leggi il numero di azioni. Ogni azione è una delle seguenti:

    • status: stampa lo stato del personaggio
    • attack: stampa [Name] attacks for [damage] damage
    • defend [amount]: applica il danno e stampa [Name] takes [actual] damage
    • setability [type] [power]: solo per i maghi, imposta l'abilità (type è fire, ice o strike)
    • useability: solo per i maghi, stampa il risultato di Use() dell'abilità

Verranno forniti i seguenti input:

  • Tipo di personaggio, nome, salute e statistiche specifiche del tipo
  • Numero di azioni, poi ogni azione su una riga separata

Ad esempio, dati:

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

Il tuo output dovrebbe essere:

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

E dati:

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

Il tuo output dovrebbe essere:

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

E dati:

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Il tuo output dovrebbe essere:

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

Nota come l'embedding delle struct consenta a ciascun tipo di personaggio di condividere i campi e i metodi di Character, mentre le interfacce permettono il combattimento polimorfico: qualsiasi Attacker può infliggere danno e qualsiasi Defender può subirlo. Il pattern Strategy dà il meglio di sé con le abilità intercambiabili del Mage: lo stesso personaggio può usare incantesimi diversi senza modificare la propria implementazione di base!

Provalo tu

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// Leggi il tipo di personaggio
	scanner.Scan()
	charType := strings.TrimSpace(scanner.Text())

	// Leggi il nome del personaggio
	scanner.Scan()
	name := strings.TrimSpace(scanner.Text())

	// Leggi i punti salute
	scanner.Scan()
	health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Leggi la prima statistica specifica del tipo
	scanner.Scan()
	stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Leggi la seconda statistica specifica del tipo
	scanner.Scan()
	stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// TODO: Crea il personaggio appropriato in base a charType
	// Usa le variabili: charType, name, health, stat1, stat2
	// Per warrior: stat1 = Strength, stat2 = Armor
	// Per mage: stat1 = Intelligence, stat2 = MagicResist
	// Per archer: stat1 = Agility, stat2 = Evasion

	// Leggi il numero di azioni
	scanner.Scan()
	numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Elabora ogni azione
	for i := 0; i < numActions; i++ {
		scanner.Scan()
		line := strings.TrimSpace(scanner.Text())
		parts := strings.Fields(line)
		action := parts[0]

		// TODO: Gestisci ogni tipo di azione:
		// - "status": stampa Status() del personaggio
		// - "attack": stampa "[Name] attacks for [damage] damage"
		// - "defend [amount]": applica il danno e stampa "[Name] takes [actual] damage"
		// - "setability [type] [power]": per i maghi, imposta l'abilità (fire, ice o strike)
		// - "useability": per i maghi, stampa il risultato di UseAbility()

		_ = action // Rimuovi questa riga durante l'implementazione
		_ = fmt.Println // Rimuovi questa riga durante l'implementazione
	}
}

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online