Roll It הוא ניסוי ב-Chrome שמציג גרסה חדשה של משחק חוף קלאסי, וניתן לשחק בו רק בדפדפן בטלפון ובמחשב. בדפדפן בטלפון אפשר לכוון את הכדור ולגלגל אותו בתנועת פרק כף היד, ואילו בדפדפן במחשב הגרפיקה של המנהרה ב-Roll It מוצגת בזמן אמת באמצעות WebGL ו-Canvas. שני המכשירים מתקשרים דרך Websockets. אין אפליקציות. אין הורדות. אין טוקנים. כל מה שצריך הוא דפדפן מודרני.
בהנחיית Google Creative Lab, חברת Legwork פיתחה את חוויית המשתמש, הממשקים ואת סביבת המשחק. לאחר מכן, היא חברה לשותף הפיתוח Mode Set כדי ליצור את Roll It. במהלך הפרויקט נתקלו בכמה אתגרים ייחודיים. במאמר הזה נסביר על כמה מהשיטות שבהן השתמשנו, על הטריקים שגילינו ועל הלקחים שלמדנו במהלך הפיתוח של Roll It.
תהליך עבודה ב-3D
אחת מהבעיות בהתחלה הייתה למצוא את הדרך הטובה ביותר להעביר מודלים תלת-ממדיים מהתוכנה שלנו לפורמט קובץ שמתאים לאינטרנט. אחרי שיצרנו את הנכסים ב-Cinema 4D, הפכנו את המודלים לפשוטים והמרנו אותם לרשתות של פוליגונים קטנים. לכל רשת ניתנו תגי בחירה מסוימים של פוליגונים כדי להבדיל בין חלקים של האובייקט לצורך צביעה והוספת טקסטורה. לאחר מכן הצלחנו לייצא כקובץ Collada 1.5 (.dae) ולייבא ל-Blender, תוכנת 3D בקוד פתוח, כדי ליצור קבצים תואמים ל-three.js. אחרי שווידאנו שהמודלים מיובאים בצורה נכונה, ייצאנו את המרקם כקובץ JSON והתאורה הופעלה באמצעות קוד. ריכזנו כאן פירוט של השלבים שביצענו:
כתיבת הקוד
Roll It פותח באמצעות ספריות קוד פתוח ופועל באופן מקורי בדפדפנים מודרניים. בעזרת טכנולוגיות כמו WebGL ו-WebSockets, האינטרנט מתקרב לחוויית משחקים וחוויית מולטימדיה באיכות של קונסולה. ככל שזמינים יותר כלים מודרניים לפיתוח HTML, כך קל יותר למפתחים ליצור את החוויות האלה.
סביבת הפיתוח
רוב הקוד המקורי של Roll It נכתב ב-CoffeeScript – שפה נקייה ותמציתית שעוברת תרגום מחדש לקוד JavaScript תקין וללא שגיאות. שפת CoffeeScript מתאימה במיוחד לפיתוח מונחה-עצמים, בזכות מודל הירושה המצוין שלה וטיפול נקי יותר בהיקף. קובץ ה-CSS נכתב באמצעות מסגרת SASS, שמספקת למפתחים מספר כלים מצוינים לשיפור ולניהול של גיליונות הסגנונות בפרויקט. הוספת המערכות האלה לתהליך ה-build דורשת קצת זמן להגדרה, אבל התוצאה בהחלט שווה את המאמץ, במיוחד בפרויקט גדול יותר כמו Roll It. הגדרנו שרת Ruby on Rails כדי לקמפל את הנכסים שלנו באופן אוטומטי במהלך הפיתוח, כך שכל שלבי הידור האלה הפכו לשקופים.
בנוסף ליצירת סביבה יעילה ונוחה לתכנות, ביצענו אופטימיזציה ידנית של הנכסים כדי לצמצם את מספר הבקשות ולטעון את האתר מהר יותר. העברנו כל תמונה דרך כמה תוכנות דחיסה – ImageOptim ו-ImageAlpha. כל תוכנית מבצעת אופטימיזציה של תמונות בדרך משלה – ללא אובדן נתונים או עם אובדן נתונים, בהתאמה. שילוב נכון של ההגדרות יכול לצמצם באופן משמעותי את גודל הקובץ של התמונה. כך לא רק חוסכים ברוחב פס בזמן טעינת תמונות חיצוניות, אלא גם לאחר האופטימיזציה, התמונות מתורגמות למחרוזות קטנות בהרבה עם קידוד base64 להטמעה בתוך שורות ב-HTML, ב-CSS וב-JavaScript. בנוגע לקידוד base64, הטמענו גם את קובצי הגופנים WOFF ו-SVG של Open Sans ישירות ב-CSS באמצעות הטכניקה הזו, וכתוצאה מכך מספר הבקשות הכולל ירד עוד יותר.
סצנת התלת-ממד עם הפיזיקה המופעלת
THREE.js היא ספריית JavaScript תלת-ממדית נפוצה לאינטרנט. הוא כולל פונקציות מתמטיות תלת-ממדיות ברמה נמוכה ואופטימיזציות של WebGL מבוססות-חומרה, שמאפשרות לאנשים רגילים ליצור בקלות סצנות תלת-ממדיות אינטראקטיביות מוארות ויפהפיות, בלי לכתוב שידורים מותאמים אישית או לבצע טרנספורמציות מטריצות ידניות. Physijs הוא מעטפת ספציפית ל-THREE.js של ספריית פיזיקה פופולרית ב-C++ שתורגמה ל-JavaScript. השתמשנו בספרייה הזו כדי לדמות את הגלילה, הקפיצה וההקפצה של הכדור לעבר היעד שלו בתלת-ממד.
מההתחלה, היעד שלנו היה לא רק ליצור חוויה פיזית ריאליסטית של גלגול הכדור, אלא גם לוודא שהאובייקטים במשחק ייראו אמיתיים. לשם כך נדרשו הרבה חזרות של התאמת כוח המשיכה הכולל של הסצנה ב-Physijs, מהירות הכדור בזמן שהוא מתגלגל מהשליפה של השחקן, השיפוע של קפיצת המסלול ומאפייני החיכוך וההחזרה (הקפיצה) של הכדור וחומרי המסלול. השילוב של יותר כוח משיכה ויותר מהירות הביא לחוויית משחק מציאותית יותר.
החלקה
רוב השילובים המודרניים של דפדפנים וכרטיסי וידאו אמורים לנצל את היתרונות של סינון רעשי עיבוד גרפי (anti-aliasing) מבוסס-חומרה בסביבת WebGL, אבל חלק מהם לא יפעלו בצורה תקינה. אם סינון הרעשי aliasing לא יפעל באופן מקורי, כל קצוות חדים עם ניגודיות גבוהה בסצנה של THREE.js יהיו מחוספסים ומכוערים (לפחות בעינינו).
למרבה המזל, יש פתרון: באמצעות קטע קוד, אנחנו יכולים לזהות אם הפלטפורמה תתמוך באופן מובנה בהחלקת קצוות. אם זה כן קורה, אנחנו מוכנים. אם לא, יש סדרה של שידורי עיבוד פוסט שמגיעים עם THREE.js שיכולים לעזור לנו. כלומר, מסנן FXAA לביטול aliasing. כשאנחנו מציירים מחדש את הסצנה שעבר רינדור בכל פריים באמצעות ה-shader הזה, בדרך כלל הקווים והקצוות נראים חלקים יותר. הדגמה:
// Check for native platform antialias support via the THREE renderer
// from: http://codeflow.org/entries/2013/feb/22/how-to-write-portable-webgl/#antialiasing
var nativeAntialiasSupport = (renderer.context.getParameter(renderer.context.SAMPLES) == 0) ? false : true;
פקדי משחק מבוססי מד תאוצה
חלק גדול מהקסם של Roll It מגיע מהמחווה של גלגול הכדור שהשחקן מבצע באמצעות הטלפון. למכשירים ניידים יש גישה למדד התנודות (accelerometer) בדפדפן כבר זמן מה, אבל בתור ענף, אנחנו רק מתחילים לבדוק זיהוי תנועות מבוסס-תנועה באינטרנט. אנחנו מוגבלים במידה מסוימת על ידי הנתונים שמספק ה-accelerometer של הטלפון, אבל עם קצת יצירתיות אנחנו יכולים ליצור חוויות חדשות ומעניינות.
זיהוי תנועת גלילה תנועת הגלילה הראשית מתחילה במעקב אחרי 10 העדכונים האחרונים של מכשיר ה-accelerometer שמגיעים מהאירוע deviceorientation
של החלון. על ידי חיסור ערך ההטיה הקודם מערך ההטיה הנוכחי, אנחנו שומרים את שינוי הזווית בין האירועים. לאחר מכן, על ידי סיכום מתמיד של ערכי הדלתה של עשרת הזוויות האחרונות, אנחנו יכולים לזהות סיבוב מתמשך כשהטלפון נע במרחב. כשהטלפון חוצה את הסף של שינוי זווית הסריקה, אנחנו מפעילים תנועה של הטלטלה. לאחר מכן, על ידי חיפוש תנועת ההטיה הגדולה ביותר בסריקה הזו, אנחנו יכולים להעריך את מהירות הכדור. ב-Roll It, המהירות הזו מתוקנת באמצעות חותמות זמן שאנחנו מצרפים לכל עדכון של תאוצה. כך אפשר לצמצם את התנודות במהירות שבה עדכוני ה-accelerometer מועברים לדפדפן במכשירים שונים.
תקשורת WebSockets
אחרי שהשחקן גורר את הכדור בטלפון, נשלחת הודעה מהטלפון למחשב הנייד עם הוראות להשקת הכדור. הודעת ה-'roll' נשלחת באמצעות אובייקט נתונים מסוג JSON דרך חיבור WebSocket בין שתי המכונות. נתוני ה-JSON קטנים, והם מורכבים בעיקר מסוג ההודעה, מהמהירות של השליפה ומכיוון הכיוון.
{
"type": "device:ball-thrown",
"speed": 0.5,
"aim": 0.1
}
כל התקשורת בין המחשב הנייד לטלפון מתבצעת באמצעות הודעות JSON קטנות כמו זו. בכל פעם שהמשחק מעדכן את המצב שלו במחשב, או שהמשתמש מטה או מקשיב על לחצן בטלפון, הודעה של WebSocket מועברת בין המכונות. כדי שהתקשורת הזו תהיה פשוטה וקלה לניהול, הודעות ה-WebSockets משודרות באמצעות נקודת יציאה אחת מכל אחד מהדפדפנים. לעומת זאת, בדפדפן המקבל יש נקודת כניסה אחת, ואובייקט WebSocket אחד מטפל בכל ההודעות הנכנסות והיוצאות בשני הקצוות. כשמתקבלת הודעת WebSocket, נתוני ה-JSON משודרים מחדש באפליקציית JavaScript באמצעות השיטה trigger()
של jQuery. בשלב הזה, הנתונים הנכנסים מתנהגים בדיוק כמו כל אירוע DOM מותאם אישית אחר, וכל אובייקט אחר באפליקציה יכול לזהות אותם ולעבד אותם.
var websocket = new WebSocket(serverIPAddress);
// rebroadcast incoming WebSocket messages with a global event via jQuery
websocket.onmessage = function(e) {
if (e.data) {
var obj = JSON.parse(e.data);
$(document).trigger(data.type, obj);
}
};
// broadcast outgoing WebSocket messages by passing in a native .js object
var broadcast = function(obj) {
websocket.send(JSON.stringify(obj));
};
שרתי ה-WebSocket של Roll It נוצרים בזמן אמת כששני מכשירים מסונכרנים עם קוד משחק. הקצה העורפי של Roll It נבנה על פלטפורמת Google Compute Engine ו-App Engine באמצעות Go.
מסכי תפריט שמטים
בנוסף להודעות WebSocket מבוססות-אירועים שמשמשות במהלך המשחק, התפריטים ב-Roll It מנוהלים על ידי הטיה של הטלפון והקשה על לחצן כדי לאשר את הבחירה. לשם כך נדרש שידור עקבי יותר של נתוני הטיה מהטלפון למחשב הנייד. כדי לצמצם את רוחב הפס ולהימנע משליחת עדכונים מיותרים, ההודעות האלה נשלחות רק אם השינוי בזווית הטיה של המכשיר הוא יותר מכמה מעלות. אין טעם לשלוח נתוני הטיה אם הטלפון מונח ישר על שולחן. גם קצב ההעברה מוגבל – לא נשלחות יותר מ-15 הודעות WebSockets בשנייה ב-Roll It, גם אם המכשיר מוטה באופן פעיל.
אחרי שהמערכת מזהה את ערכי ההטיה במחשב, היא מבצעת אינטרפולציה שלהם לאורך זמן באמצעות requestAnimationFrame
כדי לשמור על תחושה חלקה. התוצאה הסופית היא תפריט מסתובב וכדור שרוטט כדי לציין את הבחירה של המשתמש. כשהטלפון שולח נתוני הטיה, רכיבי ה-DOM האלה מתעדכנים בזמן אמת על ידי חישוב מחדש של טרנספורמציית CSS בתוך הלולאה requestAnimationFrame
. המארז של התפריט פשוט מסתובב, אבל הכדור נראה כאילו הוא מתגלגל על הרצפה. כדי להשיג את האפקט הזה, אנחנו מטמיעים טריגונומטריה בסיסית כדי לקשר את קו ה-x של הכדורים לכיוון הסיבוב שלהם. המשוואה הפשוטה היא: rotations = x / (diameter * π)
סיכום
Roll It הוא סימן לזמנים האלה. בין פרויקטי הקוד הפתוח שהניעו את הפיתוח שלו, בין כוח העיבוד של המכשירים שעל השולחן שלנו ובכיס שלנו, ובין המצב של האינטרנט כפלטפורמה, זו תקופה מרגשת ומהפכנית להיות מחוברים לאינטרנט הפתוח. רק לפני כמה שנים, חלק גדול מהטכנולוגיה הזו הייתה קיימת רק במערכות קנייניות, שלא ניתן היה להשתמש בהן ולהפיץ אותן באופן חופשי. היום אפשר ליצור חוויות מורכבות עם פחות עבודה ויותר דמיון, כי אנחנו יוצרים ומשתפים כל יום חלקים חדשים בפאזל. אז קדימה, למה אתם מחכים? אתם יכולים ליצור משהו נהדר ולשתף אותו עם העולם.