Menu
CoddyTech

RefCounted vs Node

Fa parte della sezione Programmazione orientata agli oggetti del percorso GDScript di Coddy. Lezione 43 di 65.

Ogni oggetto occupa memoria finché non viene liberato. RefCounted e Node vengono liberati in modi diversi.

Un oggetto RefCounted conta le variabili, gli array e gli oggetti che fanno riferimento a esso. Quando il conteggio scende a zero, Godot lo libera autonomamente. NOTIFICATION_PREDELETE, nel capitolo Metodi speciali, mostra il 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 written, poi Note freed
	print("Back in _ready")

note era l’unico riferimento, quindi la nota viene liberata non appena write() termina.

Un Node non viene conteggiato. Un nodo nell'albero della scena viene liberato insieme al suo genitore, e l'intero albero viene liberato quando il gioco termina. Un nodo che rimuovi dall'albero, o che non vi aggiungi mai, deve essere liberato da te:

crate.free()         # liberato subito, insieme a tutti i suoi figli
crate.queue_free()   # liberato alla fine del frame corrente

Dopo free(), il nodo non esiste più: is_instance_valid(crate) restituisce false, e chiamare un metodo su di esso è un errore. queue_free() è la scelta sicura quando altro codice potrebbe ancora usare il nodo in questo frame, ma finché il frame non termina il nodo rimane nell'albero e viene ancora conteggiato in get_child_count().

Un nodo che non viene mai liberato è una perdita di memoria: Godot segnala "ObjectDB instances were leaked at exit" quando il programma termina. Anche gli oggetti RefCounted causano perdite quando due di essi si riferiscono l'uno all'altro, perché nessuno dei due conteggi può raggiungere zero. Memorizza il collegamento in una sola direzione oppure memorizza un nome invece dell'oggetto.

Usa RefCounted per i dati: elementi, punteggi, record. Usa Node per gli oggetti che vivono nell’albero della scena.

challenge icon

Sfida

Facile

Un nodo Wave mantiene i suoi nemici come nodi figli. enemy.gd è completo: Enemy.new("Goblin", 5) crea un nodo nemico chiamato Goblin con 5 HP. Scrivi i tre metodi di Wave:

  • spawn(enemy_name, hp) aggiunge un nuovo nemico come nodo figlio. Se esiste un nodo figlio con quel nome, stampa Orc is already here e non crea nulla.
  • hit(enemy_name, damage) riduce gli hp di quel nemico e stampa Orc has 8 HP. Se gli HP sono 0 o meno, stampa Orc defeated e rimuove definitivamente il nemico, subito: la chiamata successiva a alive() non deve conteggiarlo. Se il nome non è presente, stampa No Orc here.
  • alive() restituisce quanti nemici sono rimasti.

Ogni nodo deve essere liberato: qualsiasi perdita di memoria al termine del programma fa fallire il test. Il codice fornito aggiunge l'ondata all'albero della scena, legge quanti comandi seguono (spawn Goblin 5, hit Goblin 6, count) e stampa i nemici rimasti. Con spawn Goblin 5, spawn Orc 12, hit Goblin 6, count, hit Goblin 1, spawn Orc 3, hit Orc 4 stampa:

Goblin defeated
Enemies: 1
No Goblin here
Orc is already here
Orc has 8 HP
Enemies left: 1

Il tuo codice va in wave.gd e enemy.gd. main.gd contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

extends Node

func _ready():
	# Supplied input/output code: keep it as it is
	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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore GDScript online