Menu
CoddyTech

טיפוס ברווז

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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, כתבו את המתודה הסטטית 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 אונליין