Menu
CoddyTech

مقدمة إلى الأساليب الافتراضية

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

تحتوي Python على طرائق سحرية مثل __init__ و__str__، وتستدعيها اللغة نيابةً عنك. والمكافئ في Godot هو الطريقة الافتراضية: طريقة لها اسم ثابت يبدأ بشرطة سفلية، وتعرّفها في صفك، ثم يستدعيها Godot في الوقت المناسب. لقد استخدمت اثنتين منها بالفعل:

  • تُنفَّذ _init() عندما تنشئ new() الكائن، مع الوسائط المُعطاة إلى new().
  • تُنفَّذ _ready() عندما تدخل عقدة إلى شجرة المشهد، وهي المكان الذي يبدأ فيه main.gd.

منها أيضًا _to_string()، التي تُستدعى عند طباعة كائن، وطرائق المكرّر التي تتيح لحلقة for المرور على كائن (وكلاهما في الدرسين التاليين)، و_notification()، التي تتلقى الأحداث من المحرّك. يصل أحدها، وهو NOTIFICATION_PREDELETE، قبل حذف الكائن مباشرةً:

# torch.gd
class_name Torch
extends RefCounted

var label: String

func _init(new_label: String = "Torch") -> void:
	label = new_label
	print(label, " lit")

func _notification(what: int) -> void:
	if what == NOTIFICATION_PREDELETE:
		print(label, " burned out")
# main.gd
var torch := Torch.new("Hall torch") # أُشعلت شعلة الممر
torch = null # انطفأت شعلة الممر

يُحذف كائن RefCounted بمجرد ألا يعود أي متغير يشير إليه، لذا فإن torch = null يرسل الإشعار فورًا. تجعل القيمة الافتراضية في _init() الوسيطة في new() اختيارية: ينشئ Torch.new() شعلةً تُسمى Torch.

تستخدم Python أيضًا أساليب سحرية للمعاملات، مثل __add__ للمعامل + و__eq__ للمعامل ==. لا تدعم GDScript التحميل الزائد للمعاملات: إن potion_a + potion_b خطأ. اكتب أسلوبًا بدلًا من ذلك:

# potion.gd
class_name Potion
extends RefCounted

var power: int

func _init(start_power: int) -> void:
	power = start_power

func combined(other: Potion) -> Potion:
	return Potion.new(power + other.power)

تعيد potion_a.combined(potion_b) جرعة جديدة وتترك الجرعتين الأصليتين دون تغيير. يتحقق == بين كائنين مما إذا كان الطرفان هما الكائن نفسه، وليس مما إذا كانت قيمتاهما متطابقتين: Potion.new(5) == Potion.new(5) تساوي false. اكتب طريقة مثل equals(other) عندما تحتاج إلى مقارنة القيم.

challenge icon

التحدي

سهل

اكتب الصنف Counter في counter.gd:

  • تحفظ _init(start = 0, step_size = 1) قيمة البداية في value وحجم الخطوة في step. القيم الافتراضية موجودة بالفعل في التوقيع، لذا تعمل جميع الاستدعاءات Counter.new() وCounter.new(5) وCounter.new(5, 2).
  • تضيف tick() قيمة step إلى value.
  • تحل plus(other) محل العامل +، الذي لا يتيح GDScript تعريفه: فهي تُرجع كائنًا جديدًا من Counter تكون قيمته مجموع القيمتين وخطوته هي خطوة هذا العداد. لا يتغير أي من العدادين.
  • تُرجع equals(other) القيمة true عندما تكون قيمة العدادين متساوية.

يقرأ الكود المرفق سطرين لإنشاء العدادين a وb (سطرًا فارغًا أو START أو START STEP)، ثم سطرًا واحدًا يحدد عدد مرات زيادة a وb خطوةً. ويطبع العدادين ومجموعهما، وما إذا كانت قيمتاهما متساويتين، وما إذا كان a == b. بالنسبة إلى الأسطر 5 و2 3 و3 1، يطبع:

a: 8 (step 1)
b: 5 (step 3)
a plus b: 13 (step 1)
same value: false
same object: false

ضع الكود في counter.gd. يحتوي main.gd على كود الإدخال/الإخراج المرفق ولا يمكن تعديله.

جرّب بنفسك

extends Node

func _ready():
	# كود الإدخال/الإخراج المقدَّم: اتركه كما هو
	var a := make_counter(OS.read_string_from_stdin())
	var b := make_counter(OS.read_string_from_stdin())
	var ticks := OS.read_string_from_stdin().split(" ")
	for i in int(ticks[0]):
		a.tick()
	for i in int(ticks[1]):
		b.tick()
	print("a: %d (step %d)" % [a.value, a.step])
	print("b: %d (step %d)" % [b.value, b.step])
	var total := a.plus(b)
	print("a plus b: %d (step %d)" % [total.value, total.step])
	print("same value: %s" % a.equals(b))
	print("same object: %s" % (a == b))

func make_counter(line: String) -> Counter:
	var parts := line.split(" ", false)
	if parts.is_empty():
		return Counter.new()
	if parts.size() == 1:
		return Counter.new(int(parts[0]))
	return Counter.new(int(parts[0]), int(parts[1]))
quiz iconاختبر نفسك

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

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

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