Menu
Coddy logo textTech

Système de personnages de jeu

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 107 sur 107.

challenge icon

Défi

Facile

Construisons un système de personnages de jeu qui combine l'imbrication de structures (struct embedding), les interfaces et le patron de conception Stratégie (Strategy pattern) pour créer des mécaniques de combat flexibles ! Vous allez concevoir différents types de personnages capables d'attaquer et de se défendre de manières uniques, avec des capacités interchangeables au moment de l'exécution.

Vous organiserez votre code sur cinq fichiers :

  • character.go : Définissez une structure de base Character avec les champs communs : Name (string), Health (int) et MaxHealth (int). Incluez un constructeur NewCharacter et les méthodes :
    • IsAlive() bool — retourne true si la santé est supérieure à 0
    • Status() string — retourne le format : [Name]: [Health]/[MaxHealth] HP
  • interfaces.go : Définissez les interfaces de combat qui permettent le polymorphisme :
    • Interface Attacker avec Attack() int — retourne les dégâts infligés
    • Interface Defender avec TakeDamage(damage int) int — applique la réduction de dégâts et retourne les dégâts réellement subis
    • Interface Ability avec Use() string — retourne une description de l'effet de la capacité
  • characters.go : Créez trois types de personnages qui imbriquent Character et implémentent à la fois Attacker et Defender :

    Warrior — possède un champ Strength (int) et Armor (int). Attack retourne Strength comme dégâts. TakeDamage réduit les dégâts entrants par Armor (minimum 1 dégât subi).

    Mage — possède les champs Intelligence (int) et MagicResist (int). Attack retourne Intelligence * 2 comme dégâts. TakeDamage réduit les dégâts entrants par MagicResist / 2 (minimum 1 dégât subi).

    Archer — possède les champs Agility (int) et Evasion (int). Attack retourne Agility + 5 comme dégâts. TakeDamage : si Evasion > 10, réduit les dégâts de 25 % (division entière), sinon subit la totalité des dégâts (minimum 1 dégât subi).

    Incluez des constructeurs pour chacun : NewWarrior, NewMage, NewArcher qui prennent le nom, la santé et leurs valeurs de statistiques spécifiques.

  • abilities.go : Implémentez le patron Stratégie avec des capacités interchangeables :

    Structure FireSpell avec Power (int). Son Use() retourne : Casts fireball for [Power] damage

    Structure IceSpell avec Power (int). Son Use() retourne : Casts ice shard for [Power] damage

    Structure PowerStrike avec Multiplier (int). Son Use() retourne : Performs power strike at [Multiplier]x damage

    Ajoutez un champ ability (de type Ability) à la structure Mage, avec les méthodes SetAbility(a Ability) et UseAbility() string. UseAbility retourne No ability set si la capacité est nil.

  • main.go : Créez des personnages et démontrez les mécaniques de combat.

    Lisez le type de personnage (warrior, mage ou archer), puis lisez le nom du personnage, sa santé et ses statistiques spécifiques au type. Créez le personnage approprié.

    Ensuite, lisez le nombre d'actions. Chaque action est l'une des suivantes :

    • status — affiche le statut du personnage
    • attack — affiche [Name] attacks for [damage] damage
    • defend [amount] — applique les dégâts et affiche [Name] takes [actual] damage
    • setability [type] [power] — pour les mages uniquement, définit la capacité (le type est fire, ice ou strike)
    • useability — pour les mages uniquement, affiche le résultat de Use() de la capacité

Les entrées suivantes seront fournies :

  • Type de personnage, nom, santé et statistiques spécifiques au type
  • Nombre d'actions, puis chaque action sur une ligne séparée

Par exemple, étant donné :

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

Votre sortie devrait être :

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

Et étant donné :

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

Votre sortie devrait être :

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

Et étant donné :

archer
Legolas
90
18
15
4
status
attack
defend 24
status

Votre sortie devrait être :

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

Remarquez comment l'imbrication de structures permet à chaque type de personnage de partager les champs et méthodes de base de Character, tandis que les interfaces permettent un combat polymorphe où n'importe quel Attacker peut infliger des dégâts et n'importe quel Defender peut en recevoir. Le patron Stratégie brille avec les capacités interchangeables du Mage — le même personnage peut utiliser différents sorts sans changer son implémentation de base !

Essayez vous-même

package main

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

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

	// Lire le type de personnage
	scanner.Scan()
	charType := strings.TrimSpace(scanner.Text())

	// Lire le nom du personnage
	scanner.Scan()
	name := strings.TrimSpace(scanner.Text())

	// Lire la santé
	scanner.Scan()
	health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Lire la première statistique spécifique au type
	scanner.Scan()
	stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// Lire la deuxième statistique spécifique au type
	scanner.Scan()
	stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

	// TODO: Créer le personnage approprié en fonction de charType
	// Utiliser les variables : charType, name, health, stat1, stat2
	// Pour warrior : stat1 = Strength, stat2 = Armor
	// Pour mage : stat1 = Intelligence, stat2 = MagicResist
	// Pour archer : stat1 = Agility, stat2 = Evasion

	// Lire le nombre d'actions
	scanner.Scan()
	numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))

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

		// TODO: Gérer chaque type d'action :
		// - "status" : afficher le Status() du personnage
		// - "attack" : afficher "[Name] attacks for [damage] damage"
		// - "defend [amount]" : appliquer les dégâts et afficher "[Name] takes [actual] damage"
		// - "setability [type] [power]" : pour les mages, définir la capacité (fire, ice, ou strike)
		// - "useability" : pour les mages, afficher le résultat de UseAbility()

		_ = action // Supprimer cette ligne lors de l'implémentation
		_ = fmt.Println // Supprimer cette ligne lors de l'implémentation
	}
}

Toutes les leçons de Programmation Orientée Objet