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.
Défi
FacileConstruisons 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 baseCharacteravec les champs communs :Name(string),Health(int) etMaxHealth(int). Incluez un constructeurNewCharacteret les méthodes :IsAlive() bool— retourne true si la santé est supérieure à 0Status() string— retourne le format :[Name]: [Health]/[MaxHealth] HP
interfaces.go: Définissez les interfaces de combat qui permettent le polymorphisme :- Interface
AttackeravecAttack() int— retourne les dégâts infligés - Interface
DefenderavecTakeDamage(damage int) int— applique la réduction de dégâts et retourne les dégâts réellement subis - Interface
AbilityavecUse() string— retourne une description de l'effet de la capacité
- Interface
characters.go: Créez trois types de personnages qui imbriquentCharacteret implémentent à la foisAttackeretDefender:Warrior— possède un champStrength(int) etArmor(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 champsIntelligence(int) etMagicResist(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 champsAgility(int) etEvasion(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,NewArcherqui 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
FireSpellavecPower(int). SonUse()retourne :Casts fireball for [Power] damageStructure
IceSpellavecPower(int). SonUse()retourne :Casts ice shard for [Power] damageStructure
PowerStrikeavecMultiplier(int). SonUse()retourne :Performs power strike at [Multiplier]x damageAjoutez un champ
ability(de typeAbility) à la structure Mage, avec les méthodesSetAbility(a Ability)etUseAbility() string. UseAbility retourneNo ability setsi la capacité est nil.main.go: Créez des personnages et démontrez les mécaniques de combat.Lisez le type de personnage (
warrior,mageouarcher), 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 personnageattack— affiche[Name] attacks for [damage] damagedefend [amount]— applique les dégâts et affiche[Name] takes [actual] damagesetability [type] [power]— pour les mages uniquement, définit la capacité (le type estfire,iceoustrike)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 100Votre sortie devrait être :
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damageEt étant donné :
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40Votre 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 damageEt étant donné :
archer
Legolas
90
18
15
4
status
attack
defend 24
statusVotre sortie devrait être :
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HPRemarquez 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
1Fondamentaux de la POO en Go
Fichiers externesEspace de travail et Modules GoPackages et ImportsNoms exportés vs non exportésIntroduction à la POO en GoLes Structs comme ClassesDéfinir des méthodes sur les StructsReceveurs par pointeur vs par valeurInitialisation de StructsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL'interface comme contratInterface vide (any)Assertion de typeType SwitchComposition d'interfacesInterfaces Stringer & ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter & SetterMasquage d'informations en GoRécapitulatif - Dossiers étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesContournement pour les méthodes génériquesRécapitulatif - Collections génériques13Patrons de conception, Partie 1
Introduction aux Design PatternsPatron SingletonPatron FactoryPatron Abstract FactoryPatron ObserverPatron Strategy2Exploration approfondie des Types et Structs
Types de base et compositesDéfinitions de types personnalisésTags de StructStructs anonymesStructs imbriquéesValeurs par défaut et Zero ValuesRécapitulatif - Carnet de contacts5Composition plutôt qu'héritage
Pourquoi Go n'a pas d'héritageLes bases de l'imbrication de structsPromotion de méthodesImbriquer plusieurs structsImbrication vs AgrégationMasquage de méthodes imbriquéesRécapitulatif - Hiérarchie des employés8Gestion des erreurs & POO
L'interface errorTypes d'erreurs personnalisésError Wrapping (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - File Parser11Bibliothèque standard et POO
io.Reader & io.WriterL'interface sort.InterfaceL'interface fmt.Stringerencoding/json avec les StructsL'interface http.HandlerRécapitulatif - Modèles d'API REST14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeMiddleware en tant que Décorateur3Pointeurs et Mémoire
Bases des pointeurs en GoPointeurs vers des structsPassage par valeur vs référenceLa fonction new()Garbage Collection en GoRécapitulatif - Constructeur de liste chaînée6Le polymorphisme en Go
Le polymorphisme via les interfacesLe Duck Typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif - Processeur de paiement9Concurrence et POO
Bases des GoroutinesChannels et CommunicationChannels avec buffer vs sans bufferL'instruction Selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures Thread-SafeRécapitulatif - Worker Pool