טיפוס ברווז
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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 מזהה שם שגוי של מתודה לפני שהתוכנית רצה; עם טיפוסיות ברווז, מגלים זאת רק כשהשורה רצה. השתמשו בזה עבור אובייקטים ממחלקות שאינן קשורות זו לזו וחולקים כמה מתודות.
אתגר
קלפיצוץ גורם נזק לכל מה שנמצא בקרבת מקום ויכול להיפגע. לאובייקטים אין מחלקת אב משותפת. הקבצים 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())
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםמילת המפתח selfמתודותמאפייניםבנאי (_init)חזרה – מחשבון פשוט4פולימורפיזם
חזרה על דריסת מתודותטיפוס ברווזמחלקות ומתודות אבסטרקטיותתכנון ממשקיםסיכום - מחשבון צורות2מאפייני מחלקה
משתני מופע לעומת משתנים סטטייםפונקציות סטטיותקובעי מאפייניםמאחזרי מאפייניםפרטיים לפי מוסכמהסיכום – מנהל חשבון בנק5כימוס
איברים ציבוריים ופרטייםאימות באמצעות Settersהסתרת מידעמאפיינים לקריאה בלבדסיכום – מערכת לניהול רשומות תלמידיםתרגלו בעצמכם: קומפיילר GDScript אונליין