游戏角色开发
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 64 课,共 65 课。
挑战
中等构建角色扮演游戏中的角色:一个抽象的 Character、三个扩展它的类,以及角色可以学习的技能。
character.gd 中的 Character 是一个 @abstract 类:
- 属性:
character_name(来自构造函数)、level1、max_health和health100.0、max_mana和mana50、strength、intelligence和agility10、defense5,以及作为Array[Ability]的abilities。生命值是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),其中数值均保留一位小数;如果这次攻击使生命值降至0,则发出defeated信号,并返回伤害值。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() 返回自己的类名,并使用 super() 重写 level_up():
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.gd 中的 Ability:构造函数接收 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 在线编译器