RefCounted와 Node 비교
Coddy GDScript 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 65개 중 43번째.
모든 객체는 해제될 때까지 메모리를 차지합니다. RefCounted와 Node는 서로 다른 방식으로 해제됩니다.
RefCounted 객체는 자신을 참조하는 변수, 배열, 객체의 수를 셉니다. 그 수가 0이 되면 Godot가 객체를 자동으로 해제합니다. Special Methods 장의 NOTIFICATION_PREDELETE는 그 순간을 보여 줍니다.
# 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가 출력된 다음 Note freed가 출력됨
print("Back in _ready")note가 유일한 참조였으므로 write()가 끝나자마자 note가 해제됩니다.
Node는 개수에 포함되지 않습니다. 씬 트리의 노드는 부모와 함께 해제되고, 게임이 끝나면 트리 전체가 해제됩니다. 트리에서 꺼내거나 트리에 추가하지 않은 노드는 직접 해제해야 합니다.
crate.free() # 모든 자식 노드와 함께 즉시 해제됨
crate.queue_free() # 현재 프레임이 끝날 때 해제됨free()를 호출하면 노드는 사라집니다. is_instance_valid(crate)는 false를 반환하며, 해당 노드의 메서드를 호출하면 오류가 발생합니다. 다른 코드가 이 프레임에서 여전히 노드를 사용할 수 있다면 queue_free()가 안전한 선택이지만, 이 프레임이 끝날 때까지 노드는 트리에 남아 있으며 get_child_count()에도 계속 포함됩니다.
해제되지 않는 노드는 메모리 누수입니다. 프로그램이 종료될 때 Godot은 "ObjectDB instances were leaked at exit"라고 보고합니다. 두 개의 RefCounted 객체가 서로를 참조하는 경우에도 둘 다 누수됩니다. 어느 쪽의 참조 횟수도 0이 될 수 없기 때문입니다. 링크는 한 방향으로만 저장하거나 객체 대신 이름을 저장하세요.
데이터(항목, 점수, 기록)에는 RefCounted를 사용하세요. 씬 트리에 존재하는 것에는 Node를 사용하세요.
챌린지
쉬움Wave 노드는 적을 자식 노드로 유지합니다. enemy.gd는 완성되어 있습니다. Enemy.new("Goblin", 5)는 Goblin이라는 이름의 적 노드를 생성하며, HP는 5입니다. Wave의 메서드 세 가지를 작성하세요:
spawn(enemy_name, hp)는 새로운 적을 자식으로 추가합니다. 해당 이름을 가진 자식이 있으면Orc is already here을 출력하고 아무것도 생성하지 않습니다.hit(enemy_name, damage)는 해당 적의hp를 낮추고Orc has 8 HP을 출력합니다. HP가0이하가 되면Orc defeated를 출력하고 적을 즉시 영구적으로 제거합니다. 다음alive()에서 해당 적을 세면 안 됩니다. 존재하지 않는 이름이면No Orc here를 출력합니다.alive()는 남아 있는 적의 수를 반환합니다.
모든 노드를 해제해야 합니다. 종료 시 누수가 있으면 테스트에 실패합니다. 제공된 코드는 웨이브를 장면 트리에 추가하고, 이어지는 명령의 수를 읽은 다음(spawn Goblin 5, hit Goblin 6, count) 남은 적을 출력합니다. spawn Goblin 5, spawn Orc 12, hit Goblin 6, count, hit Goblin 1, spawn Orc 3, hit Orc 4를 입력하면 다음을 출력합니다:
Goblin defeated
Enemies: 1
No Goblin here
Orc is already here
Orc has 8 HP
Enemies left: 1코드는 wave.gd와 enemy.gd에 작성합니다. main.gd에는 제공된 입력/출력 코드가 있으며 수정할 수 없습니다.
직접 해보기
extends Node
func _ready():
# 제공된 입출력 코드: 그대로 유지하세요
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())
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 GDScript 컴파일러