כתיבת Plugins ל- Unity עבור Windows Store Apps

9 ביוני 2013

no comments

Plugins Unity Windows 8 Store AppsUnity 3d היא פלטפורמת פיתוח אפליקציות ומשחקים פופולרית, שאחד מיתרונותיה הבולטים הינם התמיכה בפלטפורמות רבות. מפתחים רבים מייצאים את הפרוייקט שלהם מתוך ה- Editor של Unity לפלטפורמה ספציפית ומוסיפים תמיכה ביכולות הייחודיות שלה, לרוב ע”י שימוש ב- Plugins. בפוסט זה אסביר כיצד לכתוב Plugins ל- Unity המאפשרים להשתמש ביכולות ייחודיות של Windows 8, בעת ייצוא הפרוייקט ל- Windows Store App.

רקע: Unity Editor ו- Plugins עבור Windows Store Apps

בעוד שסביבת ה- Unity Editor היא אפליקציית דסקטופ קלאסית המבוססת על .NET (או Mono לצורך העניין), Windows Store Apps רצות ב”עולם אחר” ומשתמשות בפרופיל שונה של .NET. עולמות אלו אינם מתאימים בינארית, ו- Class Library מעולם אחד לא מתאים לעולם האחר. כמו כן, רק לאפליקציות Windows Store יש גישה ל- API’s של שכבת ה- WinRT בעוד שלאפליקציות דסקטופ אין.

המשמעות היא, שלא ניתן לקחת כל Class Library שכתבנו בעבר ולהשתמש בה כ- Plugin ב- Unity, וכן לא ניתן לקחת Class Library של Windows Store App ולהשתמש בו מתוך ה- Editor של Unity. לכן, הדרך לפתח Plugins ל- Unity עבור Windows Store App ולהשתמש בהם מתוך ה- Editor של Unity היא טיפה עקומה ומסורבלת, אך אחרי שמבינים היטב את השלבים, היא הופכת לברורה ופשוטה:

  1. ראשית, נפתח את ה- Plugin כ- Windows Store Class Library
  2. נפתח רכיב בעל אותו Interface כ- Class Library של .NET 2.0.
  3. נמקם את רכיבי ה- Plugin הנ”ל בתוך ספריית ה- Assets של הפרוייקט

כעת נעבור על התהליך שלב אחר שלב כדי ליצור תוסף פשוט שמפעיל API של WinRT – במקרה שלנו עדכון Live Tile.

1. פיתוח Plugin כ- Windows Store Class Library

ב- Visual Studio, ניצור פרוייקט חדש מסוג Class Library עבור Windows Store Apps. בדוגמא כאן קראתי לרכיב MyWinRTPlugin.

Plugins Unity Windows 8 Store Apps

Visual Studio יצר Solution חדש ובו פרוייקט בשם MyWinRTPlugin, עם מחלקה ריקה בשם Class1.cs. נשנה את שם הקובץ והמחלקה לשם ה- Plugin שלנו (במקרה הזה – LiveTiles.cs).

Plugins Unity Windows 8 Store Apps

בתוך קוד המחלקה של ה- Plugin, נכתוב את הקוד הנדרש להפעלת היכולת הייחודית של Windows 8 ע”י גישה ל- API’s של WinRT.

using Windows.UI.Notifications;

namespace MyWinRTPlugin
{
  public class LiveTiles
  {
    public bool UpdateTile(string title, string text)
    {
      // Get the template XML
      var template = TileTemplateType.TileSquareText02;
      var tileXml = TileUpdateManager.GetTemplateContent(template);

      // Edit the XML to add the text and title parameters
      var elements = tileXml.GetElementsByTagName("text");
      elements[0].AppendChild(tileXml.CreateTextNode(title));
      elements[1].AppendChild(tileXml.CreateTextNode(text));

      // Send an tile notification
      var tileNotification = new TileNotification(tileXml);
      var tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
      tileUpdater.Update(tileNotification);
      return true;
    }
  }
}

הקוד הנ”ל מכיל את המחלקה LiveTiles, המכילה מתודה אחת בשם UpdateTile המקבלת את כותרת וטקסט ושולחת עדכון Live Tile לאפליקציה, שיוצג ע”ג מסך ה- Start של המשתמש. כזכור, לצורך עדכון Live Tile נדרשת ליצור Xml ע”פ אחת התבניות האלה.

2. פיתוח רכיב בעל אותו Interface כ- Class Library של .NET 2.0.

כזכור, כיוון שה- Plugin הוא Windows Store App Class Library, הוא יכול לגשת ל- API’s של WinRT, אך לא ניתן לעשות בו שימוש באפליקציית Desktop כגון ה- Editor של Unity. כדי שבכל זאת ה- Editor יכיר את ה- Plugin, עלינו ליצור .NET Class Library באותו שם המכיל את אותו Interface של התוסף (אותו namespace, אותה מחלקה, אותן מתודות).

לשם כך, נוסיף ל- Solution פרוייקט חדש בשם MyWinRTPlugin_Unity, מסוג Windows Class Library, המשתמש ב- .NET Framework 2.0 (ניתן גם 3.0 ו- 3.5).

Plugins Unity Windows 8 Store Apps

בפרוייקט החדש, נמחק את המחלקה הריקה שנוצרה – Class1.cs.

Plugins Unity Windows 8 Store Apps

כדי לוודא שלקוד של ה- Plugin, ולפרוייקט שמיועד ל- Editor יהיו אותן חתימות תמיד, נרצה לשתף את הקובץ LiveTiles.cs עם הפרוייקט החדש. לשם כך, נגרור אותו מהפרוייקט העליון אל הפרוייקט התחתון, תוך כדי לחיצה על Alt. הדבר יוסיף Link לקובץ במקום להעתיק / להעביר אותו. לבסוף, זה יראה כך:

Plugins Unity Windows 8 Store Apps

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

Plugins Unity Windows 8 Store Apps

הסיבה היא שהפרוייקט MyWinRTPlugin מכיל קוד הפונה ל- API’s של WinRT, וכ- .NET Class Library אסור לו לעשות זאת. כדי לפתור את זה, נוסיף לקוד התוסף directives הבאים:

#if NETFX_CORE
my WinRT code here...
#endif

directives אלו מוודאים שקוד הפונה ל- API’s של WinRT נמצא רק בפרוייקטים של Windows Store Apps.

לאחר הוספתם מסביב לקטעי הקוד הפונים ל- WinRT, יראה קוד התוסף כך:

#if NETFX_CORE
using Windows.UI.Notifications;
#endif

namespace MyWinRTPlugin
{
  public class LiveTiles
  {
    public bool UpdateTile(string title, string text)
    {
#if NETFX_CORE
      // Get the template XML
      var template = TileTemplateType.TileSquareText02;
      var tileXml = TileUpdateManager.GetTemplateContent(template);

      // Edit the XML to add the text and title parameters
      var elements = tileXml.GetElementsByTagName("text");
      elements[0].AppendChild(tileXml.CreateTextNode(title));
      elements[1].AppendChild(tileXml.CreateTextNode(text));

      // Send an tile notification
      var tileNotification = new TileNotification(tileXml);
      var tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication();
      tileUpdater.Update(tileNotification);
#endif
      return true;
    }
  }
}

ע”י ביצוע הפעולות הנ”ל, דאגנו של- Assembly יש אותו Interface, אך עלינו לדאוג שבעת קומפילציה, הוא גם יקרא באותו שם של התוסף. לשם כך, נסמן את הפרוייקט MyWinRTPlugin_Unity ב- Solution Explorer, נלחץ על הכפתור הימני ונבחר ב- Properties.

Plugins Unity Windows 8 Store Apps

באזור ה- Application, נסיר את הסיומת _Unity ונוודא ששם ה- Assembly ושם ה- Default namespace זהים לאלו של ה- Plugin, במקרה שלנו: MyWinRTPlugin.

נוכל לוודא שאכן יש לנו קובץ בשם MyWinRTPlugin.dll בשני מקומות שונים.

Plugins Unity Windows 8 Store Apps

3. מיקום רכיבי ה- Plugin הנ”ל בתוך ספריית ה- Assets של הפרוייקט

נרצה שה- Editor של Unity יכיר את ה- Plugin מצד אחד ובו בזמן נרצה שבעת הייצוא של הפרוייקט ל- Windows Store App ייעשה שימוש בספרייה הנכונה.

ב- Editor, בתיקיית ה- Assets ניצור תקייה בשם Plugins ובה נוסיף את ה- Assembly של פרוייקט ה- WinRTPlugin_Unity (מסוג .NET Class Library)

Plugins Unity Windows 8 Store Apps

תחת תיקיית ה- Plugins, ניצור תקיית משנה בשם Metro ובה נשים את ה- dll של ה- Plugin (מסוג Windows Store App).

Plugins Unity Windows 8 Store Apps

פרוייקט להמחשה

לצורך ההדגמה ניצור פרוייקט בסיסי. ניצור פרוייקט Unity חדש בתיקיית הפרוייקטים (בדוגמה זו קראתי לפרוייקט החדש בשם המשמעותי New Unity Project).

Plugins Unity Windows 8 Store Apps

בפרוייקט הריק, ניצור קוביה חדשה ע”י בחירת התפריט: GameObject->Create Other->Cube.Plugins Unity Windows 8 Store Apps

נמקם את הקוביה שיצרנו בטווח הגלוי ע”י המצלמה הראשית, כך שנוכל לראות את הקוביה החלון המשחק.

Plugins Unity Windows 8 Store Apps

כעת נוסיף סקריפט בשפת C# בו נוסיף את הקוד שיפעיל בעתיד את ה- Plugin אותו אנו כותבים עבור אפליקציית Unity ל- Windows 8. בחלון ה- Project, נלחץ על כפתור ה- Create ונבחר להוסיף סקריפט.

Plugins Unity Windows 8 Store Apps

לסקריפט נקרא בשם sample ו- Unity ייצור קובץ בשם sample.cs בתיקיית ה- Assets ובו קוד בסיסי של סקריפט.

Plugins Unity Windows 8 Store Apps

נלחץ לחיצה כפולה על הסקריפט כדי לפתוח את MonoDevelop ולערוך את הסקריפט.

Plugins Unity Windows 8 Store Apps

נוסיף קוד למתודה Update שיאפשר לנו בקלות לבדוק שהוא מופעל ועובד. הקוד שנוסיף יהרוס את האובייקט הנוכחי בלחיצה על מקש הרווח.

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        Destroy(gameObject);
    }
}

נשמור את השינוי, וכשנחזור ל- Unity Editor, נוודא שהעורך רואה את ההקוד העדכני של הסקריפט.

Plugins Unity Windows 8 Store Apps

כדי להפעיל את הסקריפט על הקוביה, נגרור את הסקריפט מחלון ה- Project התחתון אל הקוביה בחלון ההיררכיה.

Plugins Unity Windows 8 Store Apps

נבדוק את התוצר שלנו. נריץ את הסצינה ע”י לחיצה על מקש ה- Play, וכאשר המשחק פעיל, נלחץ על מקש הרווח, כדי לראות שהקוביה נעלמת.

Plugins Unity Windows 8 Store Apps

כעת יש לנו פרוייקט עליו נוכל לבדוק הפעלה של Plugins עבור Windows Store Apps ב- Unity.

נוסיף את ה- dll’s של התוסף לתיקיית ה- Plugins ולתקיית המשנה בשם Metro כפי שהוסבר קודם לכן במעלה הפוסט.

Plugins Unity Windows 8 Store Apps

נחזור לסקריפט ה- Sample שיצרנו מוקדם יותר, ונפתח אותו ב- MonoDevelop (או ב- Visual Studio). כאשר ננסה להוסיף using statement ל- namespace של ה- Plugin, סביבת הפיתוח כבר תזהה אותו ותאפשר לנו לעשות בו שימוש.

Plugins Unity Windows 8 Store Apps

במקרה שלנו, נוסיף את הקריאה למתודה UpdateTile עם הטקסטים המתאימים.

// Update is called once per frame
void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
		LiveTiles tiles = new LiveTiles();
		tiles.UpdateTile("Hello", "world");
		
        Destroy(gameObject);
    }
}

אם ננסה להפעיל את המשחק מתוך ה- Editor של Unity, המשחק לא יעדכן את ה- Live Tiles, משום שה- dll שה- Editor משתמש בו לא מכיל את המימוש (שהיה מוקף ב- #if NETFX_CORE).

רק כאשר נבצע Export לפרוייקט Windows Store App ונריץ מתוך Visual Studio, יעשה שימוש ב- dll המתאים (זה ששמנו בתיקיית ה- Metro) ובזמן ריצה יעודכן ה- Live Tile.

סיכום

בפוסט הזה הסברתי על ההבדל בין Unity Editor כאפליקציית דסקטופ לאפליקציית Windows Store, שמביא לאופן שימוש טיפה מסורבל ב- Plugins. ע”י התהליך המסודר שהצגתי כאן ניתן לפתח Plugins ל- Unity עבור Windows Store Apps ולעשות שימוש ביכולות ייחודיות של Windows 8 באפליקציות ובמשחקים שכותבים ב- Unity.

תהנו!

Add comment
facebook linkedin twitter email