כדאי ללמוד איך להשתמש ב-Gamepad API כדי לקדם את משחקי האינטרנט שלכם לרמה הבאה.
ביצת ההפתעה של הדף אופליין ב-Chrome היא אחד מהסודות השמורים ביותר בהיסטוריה ([citation needed]
,
אבל הטענה הזו מבוססת על האפקט הדרמטי). אם מקישים על מקש הרווח או מקישים על הדינוזאור במכשירים ניידים, הדף אופליין הופך למשחק ארקייד שאפשר לשחק בו. יכול להיות שתשימו לב שאתם לא צריכים לעבור למצב אופליין אם מתחשק לכם לשחק: ב-Chrome תוכלו פשוט לנווט אל about://dino
, או, לחנונים שבפנים, לגלוש אל about://network-error/-106
. אבל האם ידעתם
ש-270 מיליון משחקי Chrome Dino משחקים בכל חודש?
עובדה נוספת שניתן לדעת על כך שעדיף להכיר היא שבמצב ארקייד אפשר לשחק עם הגיימפאד. נכון למועד כתיבת ההודעה הזו, נוספה תמיכה בגיימפאד לפני כשנה, בהתחייבות של Reilly Grant. כפי שניתן לראות, המשחק, בדיוק כמו שאר הפרויקט ב-Chromium, הוא קוד פתוח במלואו. בפוסט הזה אני רוצה להראות לכם איך להשתמש ב-Gamepad API.
איך משתמשים ב-Gamepad API
זיהוי תכונות ותמיכה בדפדפן
ל-Gamepad API יש תמיכה מעולה בדפדפנים במחשבים ובניידים. אפשר לבדוק אם יש תמיכה ב-Gamepad API באמצעות קטע הקוד הבא:
if ('getGamepads' in navigator) {
// The API is supported!
}
איך הדפדפן מייצג גיימפאד
הדפדפן מייצג גיימפאד כאובייקטים Gamepad
. ל-Gamepad
יש את המאפיינים (properties) הבאים:
id
: מחרוזת זיהוי לגיימפאד. המחרוזת הזו מזהה את המותג או הסגנון של מכשיר הגיימפאד המחובר.displayId
:VRDisplay.displayId
שלVRDisplay
המשויך (אם רלוונטי).index
: האינדקס של הגיימפאד בניווט.connected
: מציין אם הגיימפאד עדיין מחובר למערכת.hand
: טיפוסים בני מנייה (enum) שקובעים באיזו יד שלט רחוק מוחזק, או שסביר להניח שהוא יחזיק בה.timestamp
: הפעם האחרונה שהנתונים של הגיימפאד הזה עודכנו.mapping
: מיפוי הלחצן והצירים שבשימוש במכשיר הזה –"standard"
או"xr-standard"
.pose
: אובייקטGamepadPose
שמייצג את פרטי התנוחה שמשויכת לבקרת WebVR.axes
: מערך של ערכים לכל הצירים של הגיימפאד, מנורמלים באופן לינארי לטווח של-1.0
עד1.0
.buttons
: מערך של מצבי לחצנים לכל הלחצנים בגיימפאד.
חשוב לזכור שהלחצנים יכולים להיות דיגיטליים (לחצים או לא לחוצים) או אנלוגיים (לדוגמה, לחיצה של 78%). לכן לחצנים מדווחים כאובייקטים GamepadButton
עם המאפיינים הבאים:
pressed
: המצב שנלחץ (true
אם לוחצים על הלחצן, ו-false
אם לא לוחצים עליו.touched
: המצב שבו הלחצן נגע. אם הלחצן יכול לזהות מגע, המאפיין הזה הואtrue
אם נוגעים בלחצן. אחרת, המאפייןfalse
.value
: בלחצנים עם חיישן אנלוגי, המאפיין הזה מייצג את כמות הלחיצה על הלחצן, מנורמל לינארי בטווח שבין0.0
ל-1.0
.hapticActuators
: מערך שמכיל אובייקטיםGamepadHapticActuator
, שכל אחד מהם מייצג חומרת משוב פיזי שזמינה בבקר.
דבר נוסף שעשוי לקרות, בהתאם לדפדפן וללוח המשחקים שיש לכם, הוא מאפיין vibrationActuator
. הוא מאפשר שני סוגים של אפקטים של רעש:
- Dual-Rumble: אפקט המשוב הפיזי שנוצר על ידי שני מפעילי מסה אקסצנטריים מסתובבים, אחד בכל אחת מנקודות האחיזה בגיימפאד.
- טריגר התווספות משוב (Trigger-Rumble): אפקט המשוב הפיזי שנוצר על ידי שני מנועים עצמאיים, כשמנוע אחד ממוקם בכל אחד מהטריגרים של הגיימפאד.
בסקירה הסכימה הבאה, ישרה לפי המפרט, מוצגים המיפוי והסידור של הלחצנים והצירים בגיימפאד גנרי.
קבלת התראה כשמתבצע חיבור של גיימפאד
כדי לדעת מתי גיימפאד מחובר, מקישים על האירוע gamepadconnected
שמופעל באובייקט window
. כשהמשתמש מחבר גיימפאד, פעולה יכולה להתרחש באמצעות USB או באמצעות Bluetooth, מופעל GamepadEvent
שכולל את פרטי הגיימפאד בנכס gamepad
בשם הנכון.
בקטע הבא אפשר לראות דוגמה בשלט רחוק של Xbox 360 ששכבה בו (כן, אני אוהבת גיימינג בסגנון רטרו).
window.addEventListener('gamepadconnected', (event) => {
console.log('✅ 🎮 A gamepad was connected:', event.gamepad);
/*
gamepad: Gamepad
axes: (4) [0, 0, 0, 0]
buttons: (17) [GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton]
connected: true
id: "Xbox 360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"
index: 0
mapping: "standard"
timestamp: 6563054.284999998
vibrationActuator: GamepadHapticActuator {type: "dual-rumble"}
*/
});
התראה כשמנתקים את הגיימפאד
קבלת ההתראות על ניתוקים מגיימפאד קורית באופן דומה לאופן הזיהוי של החיבורים.
הפעם האפליקציה מאזינה לאירוע gamepaddisconnected
. שים לב שבדוגמה הבאה, connected
נקראת עכשיו false
כשמנתקים את השלט רחוק של Xbox 360.
window.addEventListener('gamepaddisconnected', (event) => {
console.log('❌ 🎮 A gamepad was disconnected:', event.gamepad);
/*
gamepad: Gamepad
axes: (4) [0, 0, 0, 0]
buttons: (17) [GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton]
connected: false
id: "Xbox 360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"
index: 0
mapping: "standard"
timestamp: 6563054.284999998
vibrationActuator: null
*/
});
הגיימפאד ב-gameplay
שמירה של גיימפאד מתחילה בקריאה ל-navigator.getGamepads()
, שמחזירה מערך עם Gamepad
פריטים. למערך ב-Chrome תמיד יש אורך קבוע של ארבעה פריטים. אם מחוברים אל אפס או פחות מארבעה לוחות גיימפאד, הפריט יכול להיות רק null
. חשוב תמיד לבדוק את כל הפריטים במערך, ושימו לב ש-Gamepads "זוכרים" את מיקום המשבצת שלהם ולא תמיד נמצאים במשבצת הראשונה שזמינה.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
אם אחד או יותר מהגיימפאדים מחוברים אבל navigator.getGamepads()
עדיין מדווח על null
פריטים,
יכול להיות שתצטרכו 'להעיר' כל גיימפאד על ידי לחיצה על אחד מהלחצנים שלו. לאחר מכן תוכלו לדגום את המצבים של הגיימפאד בלולאת המשחקים, כפי שמוצג בקוד הבא.
const pollGamepads = () => {
// Always call `navigator.getGamepads()` inside of
// the game loop, not outside.
const gamepads = navigator.getGamepads();
for (const gamepad of gamepads) {
// Disregard empty slots.
if (!gamepad) {
continue;
}
// Process the gamepad state.
console.log(gamepad);
}
// Call yourself upon the next animation frame.
// (Typically this happens every 60 times per second.)
window.requestAnimationFrame(pollGamepads);
};
// Kick off the initial game loop iteration.
pollGamepads();
מפעיל הרטט
המאפיין vibrationActuator
מחזיר אובייקט GamepadHapticActuator
, שתואם להגדרה של מנועים או מפעילים אחרים שיכולים להפעיל כוח למטרות משוב פיזי. אפשר להפעיל אפקטים פיזיים בהתקשרות אל Gamepad.vibrationActuator.playEffect()
. סוגי האפקטים היחידים החוקיים הם 'dual-rumble'
ו-'trigger-rumble'
.
אפקטים נתמכים של ראמבל
if (gamepad.vibrationActuator.effects.includes('trigger-rumble')) {
// Trigger rumble supported.
} else if (gamepad.vibrationActuator.effects.includes('dual-rumble')) {
// Dual rumble supported.
} else {
// Rumble effects aren't supported.
}
רעשן כפול
רעשן כפול מתאר הגדרה אישית של משוב פיזי עם מנוע רטט מסה אקסצנטרי שמסתובב ומסתובב בכל יד של משחק גיימפאד סטנדרטי. בתצורה הזו, כל אחד מהמנועים יכול לרטוט את כל הגיימפאד. שתי המסות שונות, כך שניתן לשלב את ההשפעות של כל אחת מהן וליצור אפקטים פיזיים מורכבים יותר. אפקטים של רעש כפול מוגדרים באמצעות ארבעה פרמטרים:
duration
: להגדרת משך אפקט הרטט באלפיות השנייה.startDelay
: מגדירה את משך ההשהיה עד שהרטט יתחיל.strongMagnitude
ו-weakMagnitude
: קובעים את רמות עוצמת הרטט למנועי המסה האקסצנטריים הכבדים והקלים יותר, מנורמלים לטווח0.0
-1.0
.
// This assumes a `Gamepad` as the value of the `gamepad` variable.
const dualRumble = (gamepad, delay = 0, duration = 100, weak = 1.0, strong = 1.0) => {
if (!('vibrationActuator' in gamepad)) {
return;
}
gamepad.vibrationActuator.playEffect('dual-rumble', {
// Start delay in ms.
startDelay: delay,
// Duration in ms.
duration: duration,
// The magnitude of the weak actuator (between 0 and 1).
weakMagnitude: weak,
// The magnitude of the strong actuator (between 0 and 1).
strongMagnitude: strong,
});
};
הפעלת רעשן
רעש הטריגרים הוא אפקט המשוב הפיזי שמופק על ידי שני מנועים עצמאיים, כשמנוע אחד ממוקם בכל אחד מהטריגרים של הגיימפאד.
// This assumes a `Gamepad` as the value of the `gamepad` variable.
const triggerRumble = (gamepad, delay = 0, duration = 100, weak = 1.0, strong = 1.0) => {
if (!('vibrationActuator' in gamepad)) {
return;
}
// Feature detection.
if (!('effects' in gamepad.vibrationActuator) || !gamepad.vibrationActuator.effects.includes('trigger-rumble')) {
return;
}
gamepad.vibrationActuator.playEffect('trigger-rumble', {
// Duration in ms.
duration: duration,
// The left trigger (between 0 and 1).
leftTrigger: leftTrigger,
// The right trigger (between 0 and 1).
rightTrigger: rightTrigger,
});
};
שילוב עם מדיניות ההרשאות
במפרט של Gamepad API מוגדר תכונה מבוקרת שהמחרוזת "gamepad"
מזהה. ערך ברירת המחדל של allowlist
הוא "self"
. מדיניות ההרשאות של המסמך קובעת אם לתוכן כלשהו במסמך הזה מותר לגשת אל navigator.getGamepads()
. אם המדיניות מושבתת באף מסמך, לא תהיה אפשרות להשתמש בתוכן במסמך navigator.getGamepads()
, וגם האירועים gamepadconnected
ו-gamepaddisconnected
לא יופעלו.
<iframe src="index.html" allow="gamepad"></iframe>
הדגמה (דמו)
בדוגמה הבאה מוטמעת הדגמה של בודק גיימפאד. קוד המקור זמין ב-Glitch. נסה את ההדגמה על ידי חיבור גיימפאד באמצעות USB או Bluetooth, לחיצה על אחד מהלחצנים שלו או הזזת צירו.
בונוס: כדאי לשחק ב-Chrome Dino באתר web.dev
תוכלו לשחק ב-Chrome Dino עם הגיימפאד באתר הזה. קוד המקור זמין ב-GitHub.
כדאי לראות את הטמעת הסקרים של הגיימפאד ב-trex-runner.js
ולראות איך מתבצע אמולציה של לחיצות על מקשים.
כדי שההדגמה של Chrome dino Gamepad תפעל, מחקתי את משחק Chrome dino מהפרויקט המרכזי של Chromium (עדכון בוצע קודם על ידי ארנל בלאן), הצבתי אותו באתר עצמאי, הרחבתי את הטמעת ה-API של הגיימפאד הקיים על ידי הוספת אפקטים של הנמכה ורטט, יצרתי מצב מסך מלא ומצב הטמעה של Mehul Satardekar. גיימינג שמח!
קישורים שימושיים
אישורים
המסמך הזה נבדק על ידי פרנסואה בופורט וג'ו מדלי. המפרט של Gamepad API נערך על ידי סטיב אגוסטון, ג'יימס הולייר ומאט ריינולדס. עורכי המפרט הקודמים הם ברנדון ג'ונס, סקוט גרהאם וטד מילצ'ארק. המפרט של תוספי Gamepad נערך על ידי Brandon Jones. תמונה ראשית (Hero) מאת לורה טורנט פואיג.