Menu
CoddyTech
flag Ar iconالعربيةdown icon

RefCounted مقابل Node

جزء من قسم البرمجة كائنية التوجّه في رحلة GDScript على Coddy. الدرس 43 من 65.

يشغل كل كائن مساحة في الذاكرة إلى أن يتم تحريرها. يتم تحرير RefCounted وNode بطرق مختلفة.

يحصي الكائن RefCounted المتغيرات والمصفوفات والكائنات التي تشير إليه. عندما ينخفض العدد إلى صفر، يحرره Godot تلقائيًا. يوضّح 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()          # كُتبت الملاحظة، ثم حُرِّرت
	print("Back in _ready")

كان note المرجع الوحيد، لذا يُحرَّر المقطع الصوتي فور انتهاء write().

لا يُحتسب 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 أيضًا عندما يشير اثنان منها إلى بعضهما، لأن عدد المراجع لأيٍّ منهما لا يمكن أن يصل إلى الصفر. خزّن الرابط في اتجاه واحد فقط، أو خزّن اسمًا بدلًا من الكائن.

استخدم RefCounted للبيانات: العناصر، والنتائج، والسجلات. واستخدم Node للأشياء التي تعيش في شجرة المشهد.

challenge icon

التحدي

سهل

تحتفظ العقدة Wave بأعدائها كعقد فرعية. الملف enemy.gd مكتمل: ينشئ Enemy.new("Goblin", 5) عقدة عدو اسمها Goblin وبها 5 نقاط صحة. اكتب الطرق الثلاث لـ Wave:

  • تضيف spawn(enemy_name, hp) عدوًا جديدًا كعقدة فرعية. إذا وُجدت عقدة فرعية بهذا الاسم، تطبع Orc is already here ولا تنشئ شيئًا.
  • تقلل hit(enemy_name, damage) قيمة hp لذلك العدو وتطبع Orc has 8 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())
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجّه

تدرّب بنفسك: مترجم GDScript عبر الإنترنت