Spielcharakter-System
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 107 von 107.
Aufgabe
EinfachLassen Sie uns ein Spiel-Charakter-System entwickeln, das Struct-Einbettung, Interfaces und das Strategy-Pattern kombiniert, um flexible Kampfmechaniken zu erstellen! Sie werden verschiedene Charaktertypen entwerfen, die auf einzigartige Weise angreifen und verteidigen können, mit Fähigkeiten, die zur Laufzeit ausgetauscht werden können.
Sie werden Ihren Code in fünf Dateien organisieren:
character.go: Definieren Sie ein Basis-StructCharactermit den gemeinsamen Feldern:Name(string),Health(int) undMaxHealth(int). Fügen Sie einenNewCharacter-Konstruktor und folgende Methoden hinzu:IsAlive() bool— gibt true zurück, wenn die Gesundheit größer als 0 istStatus() string— gibt das Format zurück:[Name]: [Health]/[MaxHealth] HP
interfaces.go: Definieren Sie die Kampf-Interfaces, die Polymorphismus ermöglichen:Attacker-Interface mitAttack() int— gibt den verursachten Schaden zurückDefender-Interface mitTakeDamage(damage int) int— wendet Schadensreduzierung an und gibt den tatsächlich erlittenen Schaden zurückAbility-Interface mitUse() string— gibt eine Beschreibung des Fähigkeitseffekts zurück
characters.go: Erstellen Sie drei Charaktertypen, dieCharactereinbetten und sowohlAttackerals auchDefenderimplementieren:Warrior— hat einStrength(int) und einArmor(int) Feld. Attack gibt Strength als Schaden zurück. TakeDamage reduziert den eingehenden Schaden um Armor (mindestens 1 erlittener Schaden).Mage— hatIntelligence(int) undMagicResist(int) Felder. Attack gibt Intelligence * 2 als Schaden zurück. TakeDamage reduziert den eingehenden Schaden um MagicResist / 2 (mindestens 1 erlittener Schaden).Archer— hatAgility(int) undEvasion(int) Felder. Attack gibt Agility + 5 als Schaden zurück. TakeDamage: Wenn Evasion > 10, reduziere den Schaden um 25% (Ganzzahldivision), andernfalls nimm den vollen Schaden (mindestens 1 erlittener Schaden).Fügen Sie Konstruktoren für jeden Typ hinzu:
NewWarrior,NewMage,NewArcher, die Name, Gesundheit und ihre spezifischen Statuswerte entgegennehmen.abilities.go: Implementieren Sie das Strategy-Pattern mit austauschbaren Fähigkeiten:FireSpell-Struct mitPower(int). SeineUse()-Methode gibt zurück:Casts fireball for [Power] damageIceSpell-Struct mitPower(int). SeineUse()-Methode gibt zurück:Casts ice shard for [Power] damagePowerStrike-Struct mitMultiplier(int). SeineUse()-Methode gibt zurück:Performs power strike at [Multiplier]x damageFügen Sie dem Mage-Struct ein
ability-Feld (vom TypAbility) hinzu, mit den MethodenSetAbility(a Ability)undUseAbility() string. UseAbility gibtNo ability setzurück, wenn ability nil ist.main.go: Erstellen Sie Charaktere und demonstrieren Sie die Kampfmechaniken.Lesen Sie den Charaktertyp (
warrior,mageoderarcher), lesen Sie dann den Namen des Charakters, die Gesundheit und die typspezifischen Statuswerte. Erstellen Sie den entsprechenden Charakter.Lesen Sie dann die Anzahl der Aktionen. Jede Aktion ist eine der folgenden:
status— gibt den Status des Charakters ausattack— gibt[Name] attacks for [damage] damageausdefend [amount]— wendet Schaden an und gibt[Name] takes [actual] damageaussetability [type] [power]— nur für Magier, setzt die Fähigkeit (Typ istfire,iceoderstrike)useability— nur für Magier, gibt das Ergebnis von Use() der Fähigkeit aus
Die folgenden Eingaben werden bereitgestellt:
- Charaktertyp, Name, Gesundheit und typspezifische Statuswerte
- Anzahl der Aktionen, dann jede Aktion in einer separaten Zeile
Zum Beispiel, gegeben:
warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100Sollte Ihre Ausgabe wie folgt aussehen:
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damageUnd gegeben:
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40Sollte Ihre Ausgabe wie folgt aussehen:
Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damageUnd gegeben:
archer
Legolas
90
18
15
4
status
attack
defend 24
statusSollte Ihre Ausgabe wie folgt aussehen:
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HPBeachten Sie, wie die Struct-Einbettung es jedem Charaktertyp ermöglicht, die Felder und Methoden des Basis-Characters zu teilen, während Interfaces einen polymorphen Kampf ermöglichen, bei dem jeder Attacker Schaden verursachen und jeder Defender Schaden empfangen kann. Das Strategy-Pattern glänzt bei den austauschbaren Fähigkeiten des Magiers – derselbe Charakter kann verschiedene Zaubersprüche verwenden, ohne seine Kernimplementierung zu ändern!
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Charaktertyp lesen
scanner.Scan()
charType := strings.TrimSpace(scanner.Text())
// Charakternamen lesen
scanner.Scan()
name := strings.TrimSpace(scanner.Text())
// Lebenspunkte lesen
scanner.Scan()
health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Ersten typspezifischen Wert lesen
scanner.Scan()
stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Zweiten typspezifischen Wert lesen
scanner.Scan()
stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// TODO: Erstelle den entsprechenden Charakter basierend auf charType
// Verwende die Variablen: charType, name, health, stat1, stat2
// Für warrior: stat1 = Strength, stat2 = Armor
// Für mage: stat1 = Intelligence, stat2 = MagicResist
// Für archer: stat1 = Agility, stat2 = Evasion
// Anzahl der Aktionen lesen
scanner.Scan()
numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Jede Aktion verarbeiten
for i := 0; i < numActions; i++ {
scanner.Scan()
line := strings.TrimSpace(scanner.Text())
parts := strings.Fields(line)
action := parts[0]
// TODO: Behandle jeden Aktionstyp:
// - "status": Status() des Charakters ausgeben
// - "attack": "[Name] attacks for [damage] damage" ausgeben
// - "defend [amount]": Schaden anwenden und "[Name] takes [actual] damage" ausgeben
// - "setability [type] [power]": Für Magier, Fähigkeit setzen (fire, ice oder strike)
// - "useability": Für Magier, Ergebnis von UseAbility() ausgeben
_ = action // Diese Zeile bei der Implementierung entfernen
_ = fmt.Println // Diese Zeile bei der Implementierung entfernen
}
}
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der Go OOP
Externe DateienGo Workspace & ModulePackages & ImportsExportierte vs. nicht-exportierte NamenEinführung in OOP in GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktor-FunktionenZusammenfassung – Einfacher Taschenrechner4Interfaces
Einführung in InterfacesImplizite ImplementierungInterface als VertragLeeres Interface (any)Type AssertionType SwitchInterface-KompositionStringer & Error InterfacesRückblick - Formen-Rechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf Paket-EbeneGetter- & Setter-MethodenInformation Hiding in GoZusammenfassung - Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterType ConstraintsGenerische StructsWorkaround für generische MethodenZusammenfassung – Generische Collection2Vertiefung: Typen & Structs
Basis- & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct TagsAnonyme StructsVerschachtelte StructsZero Values & StandardwerteZusammenfassung - Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen des Struct EmbeddingMethod PromotionEinbetten mehrerer StructsEmbedding vs. AggregationShadowing eingebetteter MethodenZusammenfassung – Mitarbeiter-Hierarchie8Fehlerbehandlung & OOP
Das error-InterfaceEigene FehlertypenError Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverZusammenfassung – Datei-Parser3Zeiger & Speicher
Zeiger-Grundlagen in GoZeiger auf StructsWertübergabe vs. ReferenzübergabeDie new() FunktionGarbage Collection in GoWiederholung – Linked List Builder6Polymorphismus in Go
Polymorphismus über InterfacesDuck Typing in GoInterface-ErfüllungsregelnPolymorphe CollectionsDependency InjectionZusammenfassung – Payment Processor9Nebenläufigkeit & OOP
Goroutines GrundlagenChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignZusammenfassung - Worker Pool