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.
Desafio
MédioCrie 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),level1,max_healthehealth100.0,max_manaemana50,strength,intelligenceeagility10,defense5eabilities, umArray[Ability]. Os valores de saúde sãofloat; os outros atributos sãoint. - Um sinal
defeated(character_name: String). - Métodos abstratos
class_title() -> Stringeattack_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. RetornaNAME reached level N!.attack(target): imprimeNAME attacks TARGETe, em seguida, retornatarget.take_damage(attack_power()).take_damage(amount) -> float: o dano éamount - defense * 0.5, mas no mínimo1.0; a saúde diminui por esse valor e nunca fica abaixo de0.0. ImprimeNAME takes D damage (HP H), com uma casa decimal para cada valor, emitedefeatedquando esse golpe reduz a saúde a0e retorna o dano.is_alive(): saúde acima de0.learn_ability(ability)adiciona a habilidade aabilities.use_ability(index, target) -> float: para um índice fora deabilities, imprimeNAME has no ability INDEXe retorna0.0; caso contrário, retorna o queuse()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úde150.0, mana30, força15, inteligência5, defesa8; poder de ataquestrength * 1.2; ao subir de nível, também recebe força+2e saúde máxima+10(saúde restaurada).Mage: saúde80.0, mana150, força5, inteligência20, defesa3; poder de ataqueintelligence * 0.4; após um ataque normal, recupera5de mana (sem ultrapassar o máximo); ao subir de nível, também recebe inteligência+2e mana máxima+15(mana restaurada).Rogue: saúde100.0, mana60, força12, inteligência8, agilidade18, defesa4; poder de ataquestrength * 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 Aragorna 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 9Seu 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
1Fundamentos da POO
Arquivos externosIntrodução à POOClasses vs. objetosA palavra-chave selfMétodosPropriedadesConstrutor (_init)Revisão - Calculadora simples4Polimorfismo
Revisitando a Sobrescrita de MétodosDuck TypingClasses e Métodos AbstratosDesign de InterfacesRevisão - Calculadora de Formas7Sinais
O que é um sinal?Declarando e emitindoConectando-se a sinaisSinais com argumentosRevisão - Sistema de saúde10Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite2Propriedades de Classe
Variáveis de Instância vs. EstáticasFunções EstáticasMétodos Setters de PropriedadeMétodos Getters de PropriedadePrivado por ConvençãoRecapitulando: Gerenciador de Conta Bancária5Encapsulamento
Membros públicos e privadosValidação com settersOcultação de informaçõesPropriedades somente para leituraRevisão - Sistema de registros de alunos8Conceitos Avançados de POO
Composição vs. HerançaClasses InternasNós como ComponentesRefCounted vs. NodeEnums em Classes3Herança
Herança básicaA palavra-chave superSobrescrita de métodosCadeias de herançaVerificações de tipo com isRevisão - Hierarquia de funcionários6Métodos especiais
Introdução aos métodos virtuaisO método _to_stringIteradores personalizadosRevisão - Lista personalizada9Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy12Desafios Finais
Plataforma de Ensino OnlineSistema BancárioDesenvolvimento de Personagens de JogosServiço de Aluguel de VeículosPratique por conta própria: Compilador de GDScript online