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 correnteDopo 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.
Sfida
FacileUn 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, stampaOrc is already heree non crea nulla.hit(enemy_name, damage)riduce glihpdi quel nemico e stampaOrc has 8 HP. Se gli HP sono0o meno, stampaOrc defeatede rimuove definitivamente il nemico, subito: la chiamata successiva aalive()non deve conteggiarlo. Se il nome non è presente, stampaNo 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: 1Il 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())
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
1Fondamenti della programmazione orientata agli oggetti
File esterniIntroduzione alla programmazione orientata agli oggettiClassi e oggetti a confrontoLa parola chiave selfMetodiProprietàCostruttore (_init)Riepilogo - Calcolatrice semplice4Polimorfismo
Ripasso dell'override dei metodiDuck typingClassi e metodi astrattiProgettazione delle interfacceRiepilogo - Calcolatore di forme7Segnali
Che cos'è un segnale?Dichiarare ed emettereCollegarsi ai segnaliSegnali con argomentiRipasso - Sistema della salute10Pattern di progettazione, parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern Composite2Proprietà delle classi
Variabili di istanza e staticheFunzioni staticheSetter delle proprietàGetter delle proprietàPrivato per convenzioneRiepilogo - Gestore di conti bancari5Incapsulamento
Membri pubblici e privatiValidazione con i setterNascondimento delle informazioniProprietà di sola letturaRiepilogo - Sistema di gestione dei dati degli studenti8Concetti avanzati di OOP
Composizione vs ereditarietàClassi interneNodi come componentiRefCounted vs NodeEnum nelle classi11Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente3Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiCatene di ereditarietàControlli di tipo con isRipasso - Gerarchia dei dipendenti6Metodi speciali
Introduzione ai metodi virtualiIl metodo _to_stringIteratori personalizzatiRiepilogo - Lista personalizzata9Modelli di progettazione, parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern ObserverPattern StrategyEsercitati da solo: Compilatore GDScript online