PROMICOGA: פרוטוקול למשחקי ארדואינו

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

וככה, במקום להשלים פוסטים ישנים ולא-גמורים שכבר החלו להעלות עובש, התחלתי לגלגל בראש רעיון חדש ומגניב (לטעמי) – ואפילו הצלחתי למצוא לו, במאמץ רב, שם שלא מופיע בגוגל: Promicoga, קיצור של Protocol for Micro Controller Gaming (פרוטוקול למשחקים במיקרו-בקרים). אז מה זה פרומיקוגה, מה זה נותן ואיך עובדים עם זה בפועל?

שפה משותפת, מימוש חופשי

הרעיון העיקרי של Promicoga הוא ליצור "שפה" משותפת ואחידה לתקשורת בין מיקרו-בקרים למיקרו-בקרים אחרים ו/או מחשבים, לצורך משחקים. למשל, אם אני אצור משחק משולב דלפי-ארדואינו ואפיץ את קובץ ה-exe, אני לא אצטרך להגיד לכם איך להרכיב את החומרה. אני רק אגיד לכם באילו פקודות Promicoga המשחק שלי משתמש, ואתם תוכלו לבנות לבד בקר משחקים מתאים, עם אילו רכיבים שתרצו ובכל קונפיגורציה שנוחה לכם!

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

להמחשה, נניח שפרוטוקול Promicoga כולל את הפקודות הבאות:

  • קוד מספרי 1 = זוז ימינה
  • קוד מספרי 2 = זוז שמאלה
  • קוד מספרי 3 = יריה

כשאני כותב משחק, נניח גרסה של "פולשים מהחלל", אני דואג שהתוכנה תפתח את הפורט הטורי (סריאלי) ותדע להגיב לשלוש הפקודות האלה שיגיעו דרכו. כשאני אפיץ את המשחק, אני אגיד לכם "שימו לב שהמשחק משתמש בפקודות 1-3 של פרומיקוגה". אתם יכולים לגשת כעת להרכבת בקר משחקים, שמבוסס על ארדואינו או כל מיקרו-בקר אחר, ולעשות את זה איך שמתחשק לכם: באמצעות שלושה לחצנים פשוטים, בעזרת חיישן מרחק ופוטורזיסטור, עם פדלים ואלקטרודות למדידת גלי מוח… לא משנה איך, העיקר שבסופו של דבר הבקר ישלח למחשב את הפקודות 1, 2 או 3 דרך הפורט הסריאלי.

וכאשר אתם תכתבו משחק אחר, למשל דמוי-Arkanoid, אתם תבנו אותו כך שיזהה את אותן פקודות – וכך כולם יוכלו לשחק בו בעזרת בקר המשחקים ששימש למשחק הקודם!

כעת, נוסיף פקודה חדשה – והפעם כזו שיוצאת בכיוון ה"הפוך": מהמחשב אל בקר המשחקים:

  • קוד מספרי 4 = התנגשות

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

הדוגמאות הללו מתארות היררכיה של קונסולה-בקר, אבל זה לא חייב להיות ככה: בעיקרון, פרומיקוגה יכול לעבוד גם עם שתי מערכות זהות – למשל משחק "צוללות" אלקטרוני, שבו כל שחקן מגיע עם לוח משלו, מחברים את הלוחות דרך החיבור הסריאלי (RX/TX) ושולחים ניחושים מצד לצד.

שיקולים טכניים

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

מהירות תקשורת: בעיקרון, תקשורת איטית תגביל את כמות המידע שאפשר להעביר הלוך-ושוב בזמן סביר. מצד שני, מהירות תקשורת גבוהה מדי עלולה להכביד על המיקרו-בקר או על תווך התקשורת – לדוגמה, אם המידע צריך לעבור בשלב כלשהו דרך רכיבי RF. מהירות "ברירת המחדל" המקובלת בארדואינו, של 9600 Baud, אמורה להספיק למשחקים פשוטים, כך שאני מציע לא להשתמש בערכים נמוכים יותר, ולהעדיף ערך ספציפי זה למען התאימות . עם זאת, לא מדובר פה בחוק – אם מישהו רוצה דווקא 14400 Baud במשחק שלו, פשוט שיציין זאת במפרט.

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

יחידות נתונים בסיסיות: היחידות ה"טבעיות" של הארדואינו ושל ספריית Serial שלו הן בייטים (bytes), וטיפוס נתונים זה מספיק בהחלט לרוב יישומי המשחקים. עם זאת, לעתים יהיה צורך בטיפוס נתונים גדול יותר – למשל, אם ננסה לשלוט במדויק בתנועה על גבי מסך מחשב בעל רזולוציה מודרנית של אלפי פיקסלים בכל ציר. לדעתי, הניגוד הרב בין הצורך (הנדיר) בדיוק לבין הצורך (החיוני) בצמצום נפח וזמן התקשורת מחייב הפרדה בין תקשורת בייטים לתקשורת של טיפוסי נתונים גדולים יותר. ההפרדה הזו תבוא לידי ביטוי בפרוטוקול.

במקביל, ישנן פקודות רבות שאינן מצריכות אפילו בייט אחד. לשם כך, חלק מתקשורת Promicoga יחולק ל-nibbles, רצפים בני ארבע ביטים בלבד.

מבנה הפקודות

כל פקודת Promicoga מתחילה ב-Header, מעין מזהה שגודלו בייט יחיד. ה-Header יתחלק לשני nibbles: הראשון (ארבעת הביטים העליונים, MSB) מציין את סוג הפקודה הנוכחית, ואילו השני (ארבעת הביטים התחתונים, LSB) מציין את הפקודה עצמה. ההפרדה בין סוג הפקודה לפקודה עצמה נועדה להקל על כותבי הקוד לסנן פקודות שאינן רלוונטיות למשחק ו/או לבקר המשחקים הספציפי שלהם.

סוגי הפקודות הבסיסיים, לפי הקודים המספריים [והבינאריים] שמייצגים אותם, הם:

  • 0 [0000] = פקודות מטא (שעוסקות בתקשורת הסריאלית עצמה, בלי קשר למשחק)
  • 2 [0010] = פקודות שליטה ברמה עליונה (משחקן אל המשחק, לדוגמה "התחל", "עצור" או "חזור לתפריט ראשי")
  • 3 [0011] = פקודות שליטה ברמה שוטפת (משחקן אל המשחק, לדוגמה "זוז ימינה", "החלף כלי נשק" או "אש")
  • 4 [0100] = פקודות משוב ברמה עליונה (מהמשחק אל שחקן, לדוגמה "Game Over", "ניצחון" או "שיא הנקודות הקודם נשבר")
  • 5 [0101] = פקודות משוב ברמה שוטפת (מהמשחק אל שחקן, לדוגמה "פגיעה בקיר" או "אויב הושמד")

כפי שניתן לראות, הביט הימני (LSB) ב-nibble של סוג הפקודה מייצג את רמת הפקודה (0=עליונה, 1=שוטפת). הביט השני מימין מציין אם מדובר בפקודת שליטה, והשלישי מימין מציין אם מדובר בפקודת משוב. הביט השמאלי נשאר פנוי לשימושים עתידיים.

הפקודות

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

הג'ויסטיק הקלאסי שולח למחשב פקודות דיסקרטיות (במובן המתמטי של המילה, כלומר בדידוֹת): "ימינה", "שמאלה", "למעלה" או "למטה". הוא אינו אומר, למשל, כמה רחוק ללכת ימינה. משטח מגע, לעומת זאת, הוא רציף מטבעו: הוא מעביר למחשב קואורדינטות מספריות מדויקות.

במשחקים פשוטים כמו "פולשים מהחלל" יש ציר תנועה אחד בלבד שהוא בשליטת השחקן: ציר X (ימין-שמאל). משחקים רבים אחרים מוסיפים שליטה בציר Y (מעלה-מטה על המסך), ואפילו בציר Z (עומק). אפרופו, בקרי משחקים מודרניים מודדים גם הטיה של הבקר במרחב על כל אחד מהצירים, אך למען הדיוק והבהירות, אם וכאשר מדידות כאלה ייתווספו לפרומיקוגה, זה לא יהיה תחת קטגוריית "תנועה" אלא תחת קטגוריה אחרת – למשל "כיוון".

פקודות עם מידע רציף עשויות לכלול, כפי שהזכרתי למעלה, נתונים גדולים יותר ממה שבייט יחיד יכול להחיל, כך שיהיו פקודות מותאמות ל-int בן 16 ביטים.

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

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

להרשמה
הודע לי על
4 Comments
מהכי חדשה
מהכי ישנה לפי הצבעות
Inline Feedbacks
הראה את כל התגובות

holy crap! וכל מילה נוספת מיותר לחלוטין.
..
ובכל זאת – איזה מגניב! כמובן שבקריאה ראשונה אני מבין רבע ממה שכתבת אבל זה רק יגרום לי לקרוא שוב ולהכנס לזה. כל הכבוד עידו!

היי עידו,
האם 4 פקודות שליטה אמורות להספיק? אתה די כובל את עצמך ל 4 פקודות לפי הייצוג הבינארי שלהם.
לדעתי היה כדאי לזוז עוד ביט אחד או שניים הצידה (לכיוון ה MSB) ולתת את הייצוג ברמה של 8/16 פקודות על.
אני אשמח לעזור במה שאפשר 🙂
מרדכי

מגניב! ברגע שאני מגיע הביתה אני מתחיל לתכנת בקר משחק!
(נשלח מסאן פרנסיסקו)