RefCounted vs Node
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 43 of 65.
Every object takes memory until it is freed. RefCounted and Node are freed in different ways.
A RefCounted object counts the variables, arrays and objects that refer to it. When the count drops to zero, Godot frees it on its own. NOTIFICATION_PREDELETE, from the Special Methods chapter, shows the 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 written, then Note freed
print("Back in _ready")note was the only reference, so the note is freed as soon as write() ends.
A Node is not counted. A node in the scene tree is freed with its parent, and the whole tree is freed when the game ends. A node that you take out of the tree, or never add to it, must be freed by you:
crate.free() # freed now, with all its children
crate.queue_free() # freed at the end of the current frameAfter free(), the node is gone: is_instance_valid(crate) returns false, and calling a method on it is an error. queue_free() is the safe choice while other code may still use the node in this frame, but until that frame ends the node stays in the tree and still counts in get_child_count().
A node that is never freed is a memory leak: Godot reports "ObjectDB instances were leaked at exit" when the program ends. RefCounted objects leak too when two of them refer to each other, because neither count can reach zero. Store the link in one direction only, or store a name instead of the object.
Use RefCounted for data: items, scores, records. Use Node for things that live in the scene tree.
Challenge
EasyA Wave node keeps its enemies as child nodes. enemy.gd is complete: Enemy.new("Goblin", 5) creates an enemy node named Goblin with 5 HP. Write the three methods of Wave:
spawn(enemy_name, hp)adds a new enemy as a child. If a child with that name exists, it printsOrc is already hereand creates nothing.hit(enemy_name, damage)lowers that enemy'shpand printsOrc has 8 HP. At0HP or less, it printsOrc defeatedand removes the enemy for good, at once: the nextalive()must not count it. A name that is not there printsNo Orc here.alive()returns how many enemies are left.
Every node must be freed: any leak at exit fails the test. The supplied code adds the wave to the scene tree, reads how many commands follow (spawn Goblin 5, hit Goblin 6, count) and prints the enemies left. For spawn Goblin 5, spawn Orc 12, hit Goblin 6, count, hit Goblin 1, spawn Orc 3, hit Orc 4 it prints:
Goblin defeated
Enemies: 1
No Goblin here
Orc is already here
Orc has 8 HP
Enemies left: 1Your code goes in wave.gd and enemy.gd. main.gd holds the supplied input/output code and cannot be edited.
Try it yourself
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())
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe self KeywordMethodsPropertiesConstructor (_init)Recap - Simple Calculator4Polymorphism
Method Overriding RevisitedDuck TypingAbstract Classes and MethodsInterface DesignRecap - Shape Calculator2Class Properties
Instance vs Static VariablesStatic FunctionsProperty SettersProperty GettersPrivate by ConventionRecap - Bank Account Manager5Encapsulation
Public and Private MembersValidation with SettersInformation HidingRead-Only PropertiesRecap - Student Records System8Advanced OOP Concepts
Composition vs InheritanceInner ClassesNodes as ComponentsRefCounted vs NodeEnums in Classes11Project: Library Management
Project OverviewBook and User Classes3Inheritance
Basic InheritanceThe super KeywordMethod OverridingInheritance ChainsType Checks with isRecap - Employee Hierarchy6Special Methods
Virtual Methods IntroductionThe _to_string MethodCustom IteratorsRecap - Custom List9Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy PatternPractice on your own: Online GDScript compiler