Menu
Coddy logo textTech

פיתוח דמות במשחק

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 86 מתוך 87.

באתגר הזה תבנה מערכת לפיתוח דמויות במשחק שמדגימה את העוצמה של OOP במידול ישויות מורכבות ואינטראקטיביות.

תכנן היררכיית דמויות שבה מחלקת בסיס Character מגדירה מאפיינים משותפים כמו בריאות, שם ורמה. מחלקות ייעודיות כגון Warrior, Mage ו־Archer מרחיבות את מחלקת הבסיס באמצעות יכולות ייחודיות וסגנונות לחימה.

ממשקים משתלבים כאן באופן טבעי: Attackable יכול להגדיר שיטות לחימה, בעוד Healable מטפל ביכולות ריפוי. Mage עשוי לממש את שניהם, ואילו Warrior מתמקד רק בהתקפה.

כדאי לשקול להשתמש בתבנית Strategy להתנהגויות תקיפה שונות, ולאפשר לדמויות להחליף סגנונות לחימה באופן דינמי. תבנית State יכולה לנהל מצבים של דמויות, כמו מצב רגיל, מורעל או המום, שמשפיעים על ההתנהגות.

חשוב על הרכבה במערכות ציוד, שבהן לדמויות "יש" כלי נשק ושריון במקום לרשת מהם. השתמש במנייה עבור מחלקות דמויות או סוגי נזק, והחל כימוס כדי להגן על הנתונים הסטטיסטיים מפני שינויים לא תקינים.

challenge icon

אתגר

קל

בואו נבנה מערכת לפיתוח דמויות משחק שמדגימה את העוצמה של OOP במידול ישויות משחק מורכבות ואינטראקטיביות! תיצרו היררכיית דמויות עם סגנונות לחימה שונים, יכולות מיוחדות ומערכת מצבים שמשפיעה על התנהגות הדמויות.

תארגנו את הקוד שלכם בשבעה קבצים:

  • DamageType.java: צרו enum שמייצג סוגי נזק שונים במשחק. כללו את הערכים PHYSICAL, MAGICAL ו-RANGED. הוסיפו שדה פרטי description מסוג String, בנאי שמגדיר אותו ו-getter. לנזק פיזי צריכה להיות התיאור "brute force", לנזק קסום "arcane energy", ולנזק מטווח "precision strike".
  • Attackable.java: צרו ממשק שמגדיר יכולות לחימה. הכריזו על מתודות attack(Character target) שמחזירה String המתאר את ההתקפה, ועל getDamageType() שמחזירה DamageType.
  • Healable.java: צרו ממשק ליכולות ריפוי. הכריזו על מתודה heal(int amount) שמחזירה String המתאר את פעולת הריפוי.
  • Character.java: צרו מחלקת בסיס מופשטת לכל דמויות המשחק. כללו שדות פרטיים עבור name (String), health (int), maxHealth (int) ו-level (int). הבנאי מקבל name, maxHealth ו-level, ומגדיר בתחילה את health כך שיהיה שווה ל-maxHealth. כללו getters לכל השדות. הוסיפו מתודה מוגנת setHealth(int health) שמוודאת שה-health נשאר בין 0 ל-maxHealth. צרו מתודה takeDamage(int damage) שמפחיתה את ה-health ומחזירה "[name] takes [damage] damage! Health: [health]/[maxHealth]". הוסיפו מתודה isAlive() שמחזירה true אם health גדול מ-0. הכריזו על מתודה מופשטת getCharacterClass() שמחזירה String.
  • Warrior.java: צרו מחלקה שיורשת מ-Character ומממשת את Attackable. הוסיפו שדה פרטי strength מסוג int. הבנאי מקבל name, maxHealth, level ו-strength. ממשו את getCharacterClass() כך שתחזיר "Warrior". ממשו את getDamageType() כך שתחזיר PHYSICAL. ממשו את attack(Character target) כך שתגרום לנזק השווה ל-strength ועוד level, תקרא למתודה takeDamage של היעד ותחזיר "[name] strikes with [damageType description] for [damage] damage!" ואחריו שורה חדשה ותוצאת takeDamage.
  • Mage.java: צרו מחלקה שיורשת מ-Character ומממשת גם את Attackable וגם את Healable. הוסיפו שדות פרטיים intelligence מסוג int ו-mana מסוג int. הבנאי מקבל name, maxHealth, level, intelligence ו-mana. ממשו את getCharacterClass() כך שתחזיר "Mage". ממשו את getDamageType() כך שתחזיר MAGICAL. ממשו את attack(Character target) כך שתגרום לנזק השווה ל-intelligence כפול 2, באותו פורמט כמו ב-Warrior. ממשו את heal(int amount) כך שתרפא את הדמות (באמצעות setHealth) ותחזיר "[name] channels healing magic! Health: [health]/[maxHealth]".
  • Main.java: הפיחו חיים במערכת המשחק שלכם! תקבלו מחרוזת פקודות המופרדת בפסיקים:
    • CREATE_WARRIOR:name:maxHealth:level:strength
    • CREATE_MAGE:name:maxHealth:level:intelligence:mana
    • ATTACK:attackerName:targetName
    • HEAL:mageName:amount
    • STATUS:characterName

    נהלו אוסף של דמויות. עבדו כל פקודה והדפיסו:

    • CREATE_WARRIOR/CREATE_MAGE: [name] the [characterClass] joins the battle!
    • ATTACK: הדפיסו את תוצאת ההתקפה (ה-String שמוחזר על ידי מתודת attack)
    • HEAL: הדפיסו את תוצאת הריפוי, או [name] cannot heal אם הדמות אינה Mage
    • STATUS: [name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]

    לאחר כל הפקודות, הדפיסו --- Battle Summary --- ואחריו את הסטטוס של כל דמות.

תקבלו קלט אחד: מחרוזת הפקודות המופרדת בפסיקים.

לדוגמה, עבור הקלט CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf, הפלט שלכם יהיה:

Thorin the Warrior joins the battle!
Gandalf the Mage joins the battle!
Thorin strikes with brute force for 20 damage!
Gandalf takes 20 damage! Health: 60/80
Gandalf channels healing magic! Health: 80/80
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive
--- Battle Summary ---
Thorin (Warrior) - Level 5 - Health: 100/100 - Alive
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive

האתגר הזה משלב ירושה (היררכיית Character), מימוש של כמה ממשקים (Mage מממשת גם את Attackable וגם את Healable), enums עם מתודות (DamageType), פולימורפיזם (התייחסות אחידה לסוגי דמויות שונים) וכימוס (ניהול health מוגן) לכדי מערכת משחק מרתקת!

נסו בעצמכם

import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: השתמשו באוסף כדי לשמור את הדמויות (LinkedHashMap שומר על סדר ההוספה)
        // LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
        
        // TODO: פצלו את input לפי פסיקים כדי לקבל פקודות נפרדות
        // String[] commands = input.split(",");
        
        // TODO: עבדו כל פקודה:
        // - CREATE_WARRIOR:name:maxHealth:level:strength
        //   הדפיסו: "[name] the Warrior joins the battle!"
        // 
        // - CREATE_MAGE:name:maxHealth:level:intelligence:mana
        //   הדפיסו: "[name] the Mage joins the battle!"
        // 
        // - ATTACK:attackerName:targetName
        //   הדפיסו את תוצאת ההתקפה מהמתודה attack
        // 
        // - HEAL:mageName:amount
        //   הדפיסו את תוצאת הריפוי, או "[name] cannot heal" אם הדמות אינה Mage
        // 
        // - STATUS:characterName
        //   הדפס: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
        
        // TODO: לאחר כל הפקודות, הדפס "--- Battle Summary ---"
        // לאחר מכן הדפס את המצב של כל דמות
    }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Java אונליין