Menu
CoddyTech

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 atual

Apó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.

challenge icon

Desafio

Fácil

Um 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, imprime Orc is already here e não cria nada.
  • hit(enemy_name, damage) reduz o hp desse inimigo e imprime Orc has 8 HP. Com 0 HP ou menos, imprime Orc defeated e remove o inimigo de vez, imediatamente: o próximo alive() não deve contabilizá-lo. Um nome que não estiver presente imprime No 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: 1

Seu 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())
quiz iconTeste seus conhecimentos

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

Pratique por conta própria: Compilador de GDScript online