Menu
CoddyTech

Разработка игрового персонажа

Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 64 из 65.

challenge icon

Задание

Средне

Создай персонажей ролевой игры: абстрактный Character, три класса, которые его расширяют, и способности, которым учатся персонажи.

Character в character.gd — это класс @abstract:

  • Свойства: character_name (из конструктора), level 1, max_health и health 100.0, max_mana и mana 50, strength, intelligence и agility 10, defense 5 и abilities — массив Array[Ability]. Значения здоровья имеют тип float, остальные характеристики — int.
  • Сигнал defeated(character_name: String).
  • Абстрактные методы class_title() -> String и attack_power() -> float.
  • level_up() -> String: уровень +1, максимальное здоровье +10, максимальная мана +5, сила, интеллект, ловкость и защита +1; здоровье и мана восстанавливаются до максимума. Возвращает NAME reached level N!.
  • attack(target): выводит NAME attacks TARGET, затем возвращает target.take_damage(attack_power()).
  • take_damage(amount) -> float: урон равен amount - defense * 0.5, но составляет как минимум 1.0; здоровье уменьшается на это значение, но не опускается ниже 0.0. Выводит NAME takes D damage (HP H), где все значения указаны с одним десятичным знаком, испускает сигнал defeated, если этот удар снизил здоровье до 0, и возвращает урон.
  • is_alive(): здоровье выше 0. learn_ability(ability) добавляет способность в abilities.
  • use_ability(index, target) -> float: если индекс находится вне диапазона abilities, выводит NAME has no ability INDEX и возвращает 0.0; иначе возвращает результат вызова use() этой способности.
  • _to_string(): NAME the TITLE (level L): HP H/MAX, mana M/MAX, STR S, INT I, AGI A, DEF D; здоровье выводится с одним десятичным знаком.

Каждый подкласс вызывает конструктор родительского класса, затем задаёт свои начальные характеристики (для остальных остаются базовые значения), возвращает название класса из class_title() и переопределяет level_up() с помощью super():

  • Warrior: здоровье 150.0, мана 30, сила 15, интеллект 5, защита 8; сила атаки strength * 1.2; при повышении уровня также получает +2 к силе и +10 к максимальному здоровью (здоровье восстанавливается).
  • Mage: здоровье 80.0, мана 150, сила 5, интеллект 20, защита 3; сила атаки intelligence * 0.4; после обычной атаки восстанавливает 5 маны (не выше максимума); при повышении уровня также получает +2 к интеллекту и +15 к максимальной мане (мана восстанавливается).
  • Rogue: здоровье 100.0, мана 60, сила 12, интеллект 8, ловкость 18, защита 4; сила атаки strength * 0.5 + agility * 0.7; при повышении уровня также получает +2 к ловкости.

Ability в ability.gd: конструктор принимает ability_name, mana_cost (int) и damage (float). use(user, target) -> float выводит USER does not have enough mana for ABILITY и возвращает 0.0, если маны пользователя меньше стоимости способности. В противном случае списывает ману, выводит USER casts ABILITY on TARGET и возвращает target.take_damage(damage + user.intelligence * 0.5).

Предоставленный код подключается к сигналу defeated каждого персонажа и выводит NAME is defeated!. Для этого ввода:

hero warrior|Aragorn
hero rogue|Orc
attack Aragorn|Orc
attack Orc|Aragorn
level Aragorn
status Aragorn

вывод будет таким:

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

Твой код размести в файлах character.gd, warrior.gd, mage.gd, rogue.gd и ability.gd. В main.gd находится предоставленный код ввода/вывода, его нельзя редактировать.

Попробуйте сами

extends Node

func _ready():
	# Предоставленный код ввода/вывода: оставьте его без изменений

	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()

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор GDScript