Menu
CoddyTech

Desarrollo de personajes de videojuegos

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 64 de 65.

challenge icon

Desafío

Intermedio

Crea los personajes de un juego de rol: un Character abstracto, tres clases que lo extienden y habilidades que aprenden los personajes.

Character en character.gd es una clase @abstract:

  • Propiedades: character_name (del constructor), level 1, max_health y health 100.0, max_mana y mana 50, strength, intelligence y agility 10, defense 5 y abilities, un Array[Ability]. Los valores de salud son float; las demás estadísticas son int.
  • Una señal defeated(character_name: String).
  • Métodos abstractos class_title() -> String y attack_power() -> float.
  • level_up() -> String: nivel +1, salud máxima +10, maná máximo +5, fuerza, inteligencia, agilidad y defensa +1; la salud y el maná se rellenan hasta sus máximos. Devuelve NAME reached level N!.
  • attack(target): imprime NAME attacks TARGET y después devuelve target.take_damage(attack_power()).
  • take_damage(amount) -> float: el daño es amount - defense * 0.5, pero como mínimo 1.0; la salud disminuye en esa cantidad y nunca baja de 0.0. Imprime NAME takes D damage (HP H) con un decimal en cada valor, emite defeated cuando este golpe reduce la salud a 0 y devuelve el daño.
  • is_alive(): salud superior a 0. learn_ability(ability) añade la habilidad a abilities.
  • use_ability(index, target) -> float: si el índice está fuera de abilities, imprime NAME has no ability INDEX y devuelve 0.0; de lo contrario, devuelve lo que devuelve el use() de la habilidad.
  • _to_string(): NAME the TITLE (level L): HP H/MAX, mana M/MAX, STR S, INT I, AGI A, DEF D; la salud lleva un decimal.

Cada subclase llama al constructor de la clase padre y luego establece sus propias estadísticas iniciales (las demás conservan los valores base), devuelve el nombre de su clase desde class_title() y sobrescribe level_up() con super():

  • Warrior: salud 150.0, maná 30, fuerza 15, inteligencia 5, defensa 8; poder de ataque strength * 1.2; al subir de nivel también obtiene fuerza +2 y salud máxima +10 (la salud se rellena).
  • Mage: salud 80.0, maná 150, fuerza 5, inteligencia 20, defensa 3; poder de ataque intelligence * 0.4; después de un ataque normal recupera 5 de maná (sin superar el máximo); al subir de nivel también obtiene inteligencia +2 y maná máximo +15 (el maná se rellena).
  • Rogue: salud 100.0, maná 60, fuerza 12, inteligencia 8, agilidad 18, defensa 4; poder de ataque strength * 0.5 + agility * 0.7; al subir de nivel también obtiene agilidad +2.

Ability en ability.gd: el constructor recibe ability_name, mana_cost (int) y damage (float). use(user, target) -> float imprime USER does not have enough mana for ABILITY y devuelve 0.0 cuando el maná del usuario es inferior al coste. De lo contrario, consume el maná, imprime USER casts ABILITY on TARGET y devuelve target.take_damage(damage + user.intelligence * 0.5).

El código proporcionado se conecta a la señal defeated de cada personaje e imprime NAME is defeated!. Para esta entrada:

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

la salida es:

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

Tu código va en character.gd, warrior.gd, mage.gd, rogue.gd y ability.gd. main.gd contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: mantenlo tal 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 las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online