Menu
CoddyTech

RefCounted vs. Node

Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 43 von 65.

Jedes Objekt belegt Speicher, bis es freigegeben wird. RefCounted und Node werden auf unterschiedliche Weise freigegeben.

Ein RefCounted-Objekt zählt die Variablen, Arrays und Objekte, die auf es verweisen. Sinkt der Zähler auf null, gibt Godot es selbst frei. NOTIFICATION_PREDELETE aus dem Kapitel „Spezielle Methoden“ zeigt diesen Moment:

# 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 geschrieben, dann Note freigegeben
	print("Back in _ready")

note war die einzige Referenz, daher wird die Notiz freigegeben, sobald write() endet.

Ein Node wird nicht mitgezählt. Ein Knoten im Szenenbaum wird zusammen mit seinem übergeordneten Knoten freigegeben, und der gesamte Baum wird freigegeben, wenn das Spiel endet. Einen Knoten, den du aus dem Baum entfernst oder gar nicht erst hinzufügst, musst du selbst freigeben:

crate.free()         # wird jetzt zusammen mit allen untergeordneten Knoten freigegeben
crate.queue_free()   # wird am Ende des aktuellen Frames freigegeben

Nach free() ist der Node verschwunden: is_instance_valid(crate) gibt false zurück, und der Aufruf einer Methode darauf ist ein Fehler. queue_free() ist die sichere Wahl, solange anderer Code den Node in diesem Frame noch verwenden könnte. Bis dieser Frame jedoch endet, bleibt der Node im Baum und wird bei get_child_count() weiterhin mitgezählt.

Ein Knoten, der nie freigegeben wird, ist ein Speicherleck: Godot meldet „ObjectDB instances were leaked at exit“, wenn das Programm endet. Auch RefCounted-Objekte verursachen Speicherlecks, wenn zwei von ihnen aufeinander verweisen, weil keiner ihrer Zähler null erreichen kann. Speichere die Verknüpfung nur in eine Richtung oder speichere statt des Objekts einen Namen.

Verwende RefCounted für Daten: Gegenstände, Punktzahlen, Datensätze. Verwende Node für Dinge, die im Szenenbaum leben.

challenge icon

Aufgabe

Einfach

Ein Wave-Knoten verwaltet seine Gegner als Kindknoten. enemy.gd ist vollständig: Enemy.new("Goblin", 5) erstellt einen Gegnerknoten mit dem Namen Goblin und 5 HP. Schreibe die drei Methoden von Wave:

  • spawn(enemy_name, hp) fügt einen neuen Gegner als Kind hinzu. Wenn bereits ein Kind mit diesem Namen existiert, gibt die Methode Orc is already here aus und erstellt nichts.
  • hit(enemy_name, damage) verringert die hp dieses Gegners und gibt Orc has 8 HP aus. Bei höchstens 0 HP gibt die Methode Orc defeated aus und entfernt den Gegner endgültig und sofort: Der nächste Aufruf von alive() darf ihn nicht mehr mitzählen. Für einen Namen, der nicht vorhanden ist, wird No Orc here ausgegeben.
  • alive() gibt zurück, wie viele Gegner noch übrig sind.

Jeder Knoten muss freigegeben werden: Jeder Speicherverlust beim Beenden lässt den Test fehlschlagen. Der bereitgestellte Code fügt die Welle dem Szenenbaum hinzu, liest, wie viele Befehle folgen (spawn Goblin 5, hit Goblin 6, count) und gibt die verbleibenden Gegner aus. Bei spawn Goblin 5, spawn Orc 12, hit Goblin 6, count, hit Goblin 1, spawn Orc 3, hit Orc 4 gibt er Folgendes aus:

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

Dein Code gehört in wave.gd und enemy.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

extends Node

func _ready():
	# Vorgegebener Ein-/Ausgabecode: unverändert lassen
	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 dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-GDScript-Compiler