Entwicklung von Spielfiguren
Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 64 von 65.
Aufgabe
MittelErstelle die Charaktere eines Rollenspiels: eine abstrakte Character-Klasse, drei Klassen, die sie erweitern, und Fähigkeiten, die Charaktere erlernen.
Character in character.gd ist eine @abstract-Klasse:
- Eigenschaften:
character_name(aus dem Konstruktor),level1,max_healthundhealth100.0,max_manaundmana50,strength,intelligenceundagility10,defense5sowieabilities, einArray[Ability]. Gesundheitswerte sindfloat, die anderen Werteint. - Ein Signal
defeated(character_name: String). - Abstrakte Methoden
class_title() -> Stringundattack_power() -> float. level_up() -> String: Level+1, maximale Gesundheit+10, maximales Mana+5, Stärke, Intelligenz, Beweglichkeit und Verteidigung jeweils+1; Gesundheit und Mana werden bis zum jeweiligen Maximum aufgefüllt. GibtNAME reached level N!zurück.attack(target): gibtNAME attacks TARGETaus und gibt anschließendtarget.take_damage(attack_power())zurück.take_damage(amount) -> float: Der Schaden beträgtamount - defense * 0.5, mindestens jedoch1.0; die Gesundheit sinkt um diesen Betrag, aber niemals unter0.0. GibtNAME takes D damage (HP H)aus, wobei alle Werte eine Nachkommastelle haben, löstdefeatedaus, wenn dieser Treffer die Gesundheit auf0senkt, und gibt den Schaden zurück.is_alive(): Gesundheit über0.learn_ability(ability)fügtabilitiesein Element hinzu.use_ability(index, target) -> float: Liegt der Index außerhalb vonabilities, wirdNAME has no ability INDEXausgegeben und0.0zurückgegeben; andernfalls wird der Rückgabewert vonuse()der Fähigkeit zurückgegeben._to_string():NAME the TITLE (level L): HP H/MAX, mana M/MAX, STR S, INT I, AGI A, DEF D, Gesundheit mit einer Nachkommastelle.
Jede Unterklasse ruft den Konstruktor der Elternklasse auf und legt dann ihre eigenen Startwerte fest (die übrigen behalten die Basiswerte), gibt ihren Klassennamen von class_title() zurück und überschreibt level_up() mit super():
Warrior: Gesundheit150.0, Mana30, Stärke15, Intelligenz5, Verteidigung8; Angriffskraftstrength * 1.2; beim Stufenaufstieg zusätzlich Stärke+2und maximale Gesundheit+10(Gesundheit wird aufgefüllt).Mage: Gesundheit80.0, Mana150, Stärke5, Intelligenz20, Verteidigung3; Angriffskraftintelligence * 0.4; nach einem normalen Angriff erhält die Figur5Mana zurück (niemals mehr als das Maximum); beim Stufenaufstieg zusätzlich Intelligenz+2und maximales Mana+15(Mana wird aufgefüllt).Rogue: Gesundheit100.0, Mana60, Stärke12, Intelligenz8, Beweglichkeit18, Verteidigung4; Angriffskraftstrength * 0.5 + agility * 0.7; beim Stufenaufstieg zusätzlich Beweglichkeit+2.
Ability in ability.gd: Der Konstruktor übernimmt ability_name, mana_cost (int) und damage (float). use(user, target) -> float gibt USER does not have enough mana for ABILITY aus und gibt 0.0 zurück, wenn das Mana des Benutzers unter den Kosten liegt. Andernfalls werden die Manakosten abgezogen, USER casts ABILITY on TARGET ausgegeben und target.take_damage(damage + user.intelligence * 0.5) zurückgegeben.
Der bereitgestellte Code verbindet das Signal defeated jedes Charakters und gibt NAME is defeated! aus. Für diese Eingabe:
hero warrior|Aragorn
hero rogue|Orc
attack Aragorn|Orc
attack Orc|Aragorn
level Aragorn
status Aragornlautet die Ausgabe:
Aragorn attacks Orc
Orc takes 16.0 damage (HP 84.0)
Orc attacks Aragorn
Aragorn takes 14.6 damage (HP 135.4)
Aragorn reached level 2!
Aragorn the Warrior (level 2): HP 170.0/170.0, mana 35/35, STR 18, INT 6, AGI 11, DEF 9Dein Code gehört in character.gd, warrior.gd, mage.gd, rogue.gd und ability.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.
Probier es selbst
extends Node
func _ready():
# Bereitgestellter Eingabe-/Ausgabecode: unverändert lassen
var heroes := {}
var line := OS.read_string_from_stdin()
while line != "":
var parts := line.split(" ", true, 1)
var f: PackedStringArray = parts[1].split("|") if parts.size() > 1 else PackedStringArray()
match parts[0]:
"hero":
var hero: Character
match f[0]:
"warrior":
hero = Warrior.new(f[1])
"mage":
hero = Mage.new(f[1])
"rogue":
hero = Rogue.new(f[1])
hero.defeated.connect(func(who): print(who, " is defeated!"))
heroes[f[1]] = hero
"learn":
heroes[f[0]].learn_ability(Ability.new(f[1], int(f[2]), float(f[3])))
"attack":
heroes[f[0]].attack(heroes[f[1]])
"cast":
heroes[f[0]].use_ability(int(f[1]), heroes[f[2]])
"level":
print(heroes[f[0]].level_up())
"status":
print(heroes[f[0]])
line = OS.read_string_from_stdin()
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort selfMethodenEigenschaftenKonstruktor (_init)Wiederholung – Einfacher Taschenrechner4Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypisierungAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner2Klassenattribute
Instanz- vs. statische VariablenStatische FunktionenProperty-SetterProperty-GetterPrivat nach KonventionWiederholung – Bankkontenverwaltung5Kapselung
Öffentliche und private MemberValidierung mit SetternInformationsverbergenSchreibgeschützte EigenschaftenRückblick – System zur Schülerverwaltung8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungInnere KlassenNodes als KomponentenRefCounted vs. NodeEnums in Klassen11Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungVererbungskettenTypprüfungen mit isWiederholung – Mitarbeiterhierarchie6Spezielle Methoden
Einführung in virtuelle MethodenDie _to_string-MethodeBenutzerdefinierte IteratorenRückblick – Benutzerdefinierte Liste9Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBeobachter-MusterStrategie-Muster12Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungÜbe selbstständig: Online-GDScript-Compiler