Menu
CoddyTech

Desenvolvimento de Personagens de Jogos

Parte da seção Programação orientada a objetos do Journey de GDScript da Coddy. Lição 64 de 65.

challenge icon

Desafio

Médio

Crie os personagens de um jogo de RPG: um Character abstrato, três classes que o estendem e habilidades que os personagens aprendem.

Character em character.gd é uma classe @abstract:

  • Propriedades: character_name (do construtor), level 1, max_health e health 100.0, max_mana e mana 50, strength, intelligence e agility 10, defense 5 e abilities, um Array[Ability]. Os valores de saúde são float; os outros atributos são int.
  • Um sinal defeated(character_name: String).
  • Métodos abstratos class_title() -> String e attack_power() -> float.
  • level_up() -> String: nível +1, saúde máxima +10, mana máxima +5, força, inteligência, agilidade e defesa +1; saúde e mana são restauradas até o máximo. Retorna NAME reached level N!.
  • attack(target): imprime NAME attacks TARGET e, em seguida, retorna target.take_damage(attack_power()).
  • take_damage(amount) -> float: o dano é amount - defense * 0.5, mas no mínimo 1.0; a saúde diminui por esse valor e nunca fica abaixo de 0.0. Imprime NAME takes D damage (HP H), com uma casa decimal para cada valor, emite defeated quando esse golpe reduz a saúde a 0 e retorna o dano.
  • is_alive(): saúde acima de 0. learn_ability(ability) adiciona a habilidade a abilities.
  • use_ability(index, target) -> float: para um índice fora de abilities, imprime NAME has no ability INDEX e retorna 0.0; caso contrário, retorna o que use() da habilidade retorna.
  • _to_string(): NAME the TITLE (level L): HP H/MAX, mana M/MAX, STR S, INT I, AGI A, DEF D, com a saúde exibida com uma casa decimal.

Cada subclasse chama o construtor da classe pai e, em seguida, define seus próprios atributos iniciais (os demais mantêm os valores da classe base), retorna o nome da classe em class_title() e sobrescreve level_up() usando super():

  • Warrior: saúde 150.0, mana 30, força 15, inteligência 5, defesa 8; poder de ataque strength * 1.2; ao subir de nível, também recebe força +2 e saúde máxima +10 (saúde restaurada).
  • Mage: saúde 80.0, mana 150, força 5, inteligência 20, defesa 3; poder de ataque intelligence * 0.4; após um ataque normal, recupera 5 de mana (sem ultrapassar o máximo); ao subir de nível, também recebe inteligência +2 e mana máxima +15 (mana restaurada).
  • Rogue: saúde 100.0, mana 60, força 12, inteligência 8, agilidade 18, defesa 4; poder de ataque strength * 0.5 + agility * 0.7; ao subir de nível, também recebe agilidade +2.

Ability em ability.gd: o construtor recebe ability_name, mana_cost (int) e damage (float). use(user, target) -> float imprime USER does not have enough mana for ABILITY e retorna 0.0 quando a mana do usuário é inferior ao custo. Caso contrário, desconta a mana, imprime USER casts ABILITY on TARGET e retorna target.take_damage(damage + user.intelligence * 0.5).

O código fornecido se conecta ao sinal defeated de cada personagem e imprime NAME is defeated!. Para esta entrada:

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

a saída é:

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

Seu código deve ficar em character.gd, warrior.gd, mage.gd, rogue.gd e ability.gd. main.gd contém o código de entrada/saída fornecido e não pode ser editado.

Experimente você mesmo

extends Node

func _ready():
	# Código de entrada/saída fornecido: mantenha-o como está

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

Todas as lições de Programação orientada a objetos

Pratique por conta própria: Compilador de GDScript online