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

كتابة الأنواع بأسلوب البطة

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

يهتم التنميط بأسلوب البطة بما يستطيع الكائن فعله، لا بالفئة التي ينتمي إليها. إذا كان لديه الأسلوب الذي تستدعيه، فسيعمل الاستدعاء. يأتي الاسم من المقولة: "إذا كان يسبح مثل البطة ويُصدر صوتًا مثل البطة، فهو بطة".

لا تشترك هاتان الفئتان في فئة أب خاصة بهما، لكن كلتيهما تحتويان على swim() وquack():

# duck.gd
class_name Duck
extends RefCounted

func swim() -> String:
	return "Duck swimming"

func quack() -> String:
	return "Quack!"
# robot.gd
class_name Robot
extends RefCounted

func swim() -> String:
	return "Robot swimming with propellers"

func quack() -> String:
	return "Robot sound: BEEP BEEP!"

تقبل المعلمة التي لا تملك نوعًا محددًا أي كائن. تستدعي الدالة الأساليب، وينفّذ كل كائن أساليبه الخاصة:

func make_it_swim_and_quack(thing) -> void:
	print(thing.swim())
	print(thing.quack())
make_it_swim_and_quack(Duck.new())
make_it_swim_and_quack(Robot.new())
Duck swimming
Quack!
Robot swimming with propellers
Robot sound: BEEP BEEP!

تتطلب إعادة التعريف وجود فئة أب مشتركة؛ أما الكتابة بأسلوب البط فهي لا تتطلب ذلك. عند تحديد نوع المعامل على أنه thing: Duck، فإن تمرير Robot سيؤدي إلى خطأ في التحليل.

عندما يفتقر كائن إلى الطريقة، يوقف الاستدعاء الدالة ويُظهر خطأً مثل Invalid call. Nonexistent function 'quack'. تحقّق أولًا باستخدام has_method()، التي تأخذ اسم الطريقة كسلسلة نصية:

var things := [Duck.new(), Rock.new()]
for thing in things:
	if thing.has_method("quack"):
		print(thing.quack())
	else:
		print("This one cannot quack")
Quack!
This one cannot quack

الثمن: مع الأنواع، يكتشف Godot اسم الطريقة الخاطئ قبل تشغيل البرنامج؛ أما مع الكتابة بطريقة البط، فلا تكتشف ذلك إلا عند تنفيذ السطر. استخدمها مع كائنات من أصناف غير مترابطة تشترك في بعض الطرق.

challenge icon

التحدي

سهل

يتسبب الانفجار في إلحاق الضرر بكل شيء قريب يمكنه تلقي الضرر. لا تشترك الكائنات في فئة أب. الملفان player.gd وrock.gd مكتملان: لدى Player الدالتان take_damage(amount) وstatus()، بينما لدى Rock الدالة status() فقط.

  • في crate.gd، أضف إلى Crate متغيرًا اسمه broken تكون قيمته الابتدائية false، ودالة take_damage(amount) تكسر الصندوق عندما تكون القيمة 10 أو أكثر، ودالة status() تعيد Crate: broken أو Crate: intact.
  • في explosion.gd، اكتب الدالة static hit_all(things, amount). تستدعي الدالة take_damage(amount) لكل كائن في المصفوفة Array لديه هذه الدالة، وتعيد عدد الكائنات التي أصابتها.

تقرأ الشيفرة المقدمة سطرًا من أسماء الكائنات (player أو crate أو rock)، ثم عدد الانفجارات التي ستحدث ومقدار الضرر الذي يسببه كل منها. وتطبع عدد الكائنات التي أصابها كل انفجار، ثم حالة كل كائن. عند إدخال player crate rock وانفجارين يسببان ضررًا بقيمتي 5 و20، تكون المخرجات:

Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solid

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

جرّب بنفسك

extends Node

func _ready():
	# كود الإدخال/الإخراج المقدَّم: اتركه كما هو
	var things := []
	for word in OS.read_string_from_stdin().split(" "):
		if word == "player":
			things.append(Player.new())
		elif word == "crate":
			things.append(Crate.new())
		else:
			things.append(Rock.new())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var hits := Explosion.hit_all(things, int(OS.read_string_from_stdin()))
		print("Explosion %d hit %d objects" % [i + 1, hits])
	for thing in things:
		print(thing.status())
quiz iconاختبر نفسك

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

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

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