RefCounted vs. Node
Parte da seção Programação orientada a objetos do Journey de GDScript da Coddy. Lição 43 de 65.
Cada objeto ocupa memória até ser liberado. RefCounted e Node são liberados de maneiras diferentes.
Um objeto RefCounted conta as variáveis, os arrays e os objetos que fazem referência a ele. Quando a contagem chega a zero, o Godot o libera por conta própria. NOTIFICATION_PREDELETE, do capítulo Métodos especiais, mostra o momento:
# note.gd
class_name Note
extends RefCounted
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
print("Note freed")
# main.gd
func write() -> void:
var note := Note.new()
print("Note written")
func _ready():
write() # Note escrita, depois Note liberada
print("Back in _ready")note era a única referência, então a nota é liberada assim que write() termina.
Um Node não é contado. Um nó na árvore de cena é liberado junto com seu pai, e a árvore inteira é liberada quando o jogo termina. Um nó que você remove da árvore, ou nunca adiciona a ela, deve ser liberado por você:
crate.free() # liberado agora, junto com todos os seus filhos
crate.queue_free() # liberado ao final do quadro atualApós free(), o nó desaparece: is_instance_valid(crate) retorna false, e chamar um método nele é um erro. queue_free() é a opção segura enquanto outro código ainda puder usar o nó neste quadro, mas, até o fim desse quadro, o nó permanece na árvore e ainda é contado em get_child_count().
Um nó que nunca é liberado é um vazamento de memória: Godot informa "ObjectDB instances were leaked at exit" quando o programa termina. Objetos RefCounted também causam vazamentos quando dois deles fazem referência um ao outro, porque nenhuma das contagens pode chegar a zero. Armazene o link em apenas uma direção ou armazene um nome em vez do objeto.
Use RefCounted para dados: itens, pontuações, registros. Use Node para coisas que vivem na árvore de cena.
Desafio
FácilUm nó Wave mantém seus inimigos como nós filhos. enemy.gd está completo: Enemy.new("Goblin", 5) cria um nó inimigo chamado Goblin com 5 HP. Escreva os três métodos de Wave:
spawn(enemy_name, hp)adiciona um novo inimigo como filho. Se existir um filho com esse nome, imprimeOrc is already heree não cria nada.hit(enemy_name, damage)reduz ohpdesse inimigo e imprimeOrc has 8 HP. Com0HP ou menos, imprimeOrc defeatede remove o inimigo de vez, imediatamente: o próximoalive()não deve contabilizá-lo. Um nome que não estiver presente imprimeNo Orc here.alive()retorna quantos inimigos restam.
Todos os nós devem ser liberados: qualquer vazamento ao sair reprova o teste. O código fornecido adiciona a onda à árvore de cena, lê quantos comandos vêm em seguida (spawn Goblin 5, hit Goblin 6, count) e imprime os inimigos restantes. Para spawn Goblin 5, spawn Orc 12, hit Goblin 6, count, hit Goblin 1, spawn Orc 3, hit Orc 4, ele imprime:
Goblin defeated
Enemies: 1
No Goblin here
Orc is already here
Orc has 8 HP
Enemies left: 1Seu código deve ficar em wave.gd e enemy.gd. main.gd contém o código fornecido de entrada/saída 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 wave := Wave.new()
add_child(wave)
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "spawn":
wave.spawn(parts[1], int(parts[2]))
elif parts[0] == "hit":
wave.hit(parts[1], int(parts[2]))
else:
print("Enemies: ", wave.alive())
print("Enemies left: ", wave.alive())
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
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 StrategyPratique por conta própria: Compilador de GDScript online