איך לשחק במשחק Chrome Dino באמצעות הגיימפאד

כדאי ללמוד איך להשתמש ב-Gamepad API כדי לקדם את משחקי האינטרנט שלכם לרמה הבאה.

ביצית ההפתעה של הדף אופליין של Chrome היא אחד מהסודות הגרועים ביותר בהיסטוריה ([citation needed], אלא טענה לגבי האפקט הדרמטי). אם מקישים על מקש הרווח או בנייד מכשירים, מקישים על הדינוזאור, הדף במצב אופליין הופך למשחק ארקייד שניתן לשחק בו. אולי אתם מודעים לכך אין צורך באמת לעבור למצב אופליין כשמתחשק לך לשחק: ב-Chrome, אפשר פשוט לנווט אל about://dino, או, אם אתם חנונים, היכנסו אל about://network-error/-106. אבל הידעת כי יש משחקים ב-270 מיליון משחקי דינו של Chrome בכל חודש?

דף אופליין ב-Chrome עם המשחק Chrome Dino.
צריך ללחוץ על מקש הרווח כדי לשחק.

עובדה נוספת שניתן אולי לדעת בוודאות שהיא מועילה יותר, ושאתם לא מודעים אליה במצב ארקייד, אפשר לשחק במשחק באמצעות גיימפאד. תמיכה בגיימפאד נוספה לפני שנה בערך של תקופת הכתיבה הזו commit לפי 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
  */
});

הגיימפאד בגיימפליי

אחזור של בקר משחקים מתחיל בקריאה ל-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.
}

רעשן כפול

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

  • 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,
  });
};

זמזום של הטריגר

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

// 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 Dino תפעל, צריך: לקח את משחק Chrome Dino מפרויקט הליבה של Chromium (עדכון מאמץ קודם של Arnelle Ballane), הציבה אותו באתר נפרד, הרחיבה קיימת הטמעה של Gamepad API על ידי הוספת אפקטים של הנמכה ורטט, ונוצרת מסך מלא במצב כהה, ו-Mehul Satardekar יצר מצב כהה יישום בפועל. בהצלחה בגיימינג!

אישורים

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