Menu
CoddyTech

Entwicklung von Spielfiguren

Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 64 von 65.

challenge icon

Aufgabe

Mittel

Erstelle 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), level 1, max_health und health 100.0, max_mana und mana 50, strength, intelligence und agility 10, defense 5 sowie abilities, ein Array[Ability]. Gesundheitswerte sind float, die anderen Werte int.
  • Ein Signal defeated(character_name: String).
  • Abstrakte Methoden class_title() -> String und attack_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. Gibt NAME reached level N! zurück.
  • attack(target): gibt NAME attacks TARGET aus und gibt anschließend target.take_damage(attack_power()) zurück.
  • take_damage(amount) -> float: Der Schaden beträgt amount - defense * 0.5, mindestens jedoch 1.0; die Gesundheit sinkt um diesen Betrag, aber niemals unter 0.0. Gibt NAME takes D damage (HP H) aus, wobei alle Werte eine Nachkommastelle haben, löst defeated aus, wenn dieser Treffer die Gesundheit auf 0 senkt, und gibt den Schaden zurück.
  • is_alive(): Gesundheit über 0. learn_ability(ability) fügt abilities ein Element hinzu.
  • use_ability(index, target) -> float: Liegt der Index außerhalb von abilities, wird NAME has no ability INDEX ausgegeben und 0.0 zurückgegeben; andernfalls wird der Rückgabewert von use() 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: Gesundheit 150.0, Mana 30, Stärke 15, Intelligenz 5, Verteidigung 8; Angriffskraft strength * 1.2; beim Stufenaufstieg zusätzlich Stärke +2 und maximale Gesundheit +10 (Gesundheit wird aufgefüllt).
  • Mage: Gesundheit 80.0, Mana 150, Stärke 5, Intelligenz 20, Verteidigung 3; Angriffskraft intelligence * 0.4; nach einem normalen Angriff erhält die Figur 5 Mana zurück (niemals mehr als das Maximum); beim Stufenaufstieg zusätzlich Intelligenz +2 und maximales Mana +15 (Mana wird aufgefüllt).
  • Rogue: Gesundheit 100.0, Mana 60, Stärke 12, Intelligenz 8, Beweglichkeit 18, Verteidigung 4; Angriffskraft strength * 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 Aragorn

lautet 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 9

Dein 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

Übe selbstständig: Online-GDScript-Compiler