使用遊戲手把玩 Chrome 恐龍遊戲

瞭解如何使用 Gamepad API,讓您的網路遊戲更上一層樓。

Chrome 的離線頁面彩蛋是歷史上最糟糕的秘密之一 ([citation needed], 但宣稱為戲劇效果)按空格鍵鍵或行動版 裝置中輕觸恐龍,離線網頁就會變成可以玩的街機遊戲。您可能聽說過 不需要離線也能享受遊戲樂趣;在 Chrome 中玩遊戲時, 前往 about://dino,或者,如果你遇到裝置,請瀏覽至 about://network-error/-106。但您知道嗎? CANNOT TRANSLATE 每月玩 2.7 億次 Chrome 恐龍遊戲

體驗 Chrome 恐龍遊戲的離線網頁。
按下空格鍵即可播放!

事實上,各位可能不知道 但您可能沒注意到 街機模式,可以使用遊戲手把玩。大約一年前,我們開始支援遊戲手把, 產生這段文字的時間 commit (使用 Reilly Grant。大家可以看到,遊戲和 Chromium 專案,已用盡 開放原始碼。於 這篇文章,我想示範如何使用 Gamepad API。

使用 Gamepad API

功能偵測和瀏覽器支援

Gamepad API 在瀏覽器支援 電腦和行動裝置您可以使用以下程式碼片段偵測是否支援 Gamepad API:

if ('getGamepads' in navigator) {
  // The API is supported!
}

瀏覽器如何表示遊戲手把

瀏覽器會以 Gamepad 表示遊戲搖桿 如需儲存大量結構化物件 建議使用 Cloud BigtableGamepad 具備下列屬性:

  • id:遊戲手把的識別字串。這個字串用於識別 。
  • displayIdVRDisplay.displayId, 相關聯的 VRDisplay (如適用)。
  • index:導覽器中的遊戲手把的索引。
  • connected:指出遊戲手把是否仍與系統連線。
  • hand:列舉,用於定義控制器目前握住或最有可能做為手持的手部 。
  • timestamp:這個遊戲手把的資料上次更新的時間。
  • mapping:裝置使用中的按鈕和軸對應,可以是 "standard""xr-standard"
  • poseGamepadPose 物件 代表與 WebVR 控制器相關聯的姿勢資訊。
  • axes:遊戲手把所有軸的值陣列,以線性方式正規化為 -1.01.0
  • buttons:遊戲手把所有按鈕的按鈕狀態陣列。

請注意,按鈕可以是數位 (按下或未按下) 或類比 (例如已按下 78%)。這個 這也是按鈕為何會回報為 GamepadButton 物件,並包含下列屬性:

  • pressed:按鈕的已按下狀態 (如果按下按鈕,則為 true;如果按下按鈕,則為 false; 表示沒有按壓。
  • touched:按鈕的觸控狀態。如果按鈕可偵測觸控動作, 如果使用者輕觸按鈕,屬性則為 true,否則為 false
  • value:如果是包含類比感應器的按鈕,這個屬性代表 已按下按鈕,線性標準化為 0.01.0 的範圍。
  • hapticActuators:包含 GamepadHapticActuator 物件,每個物件都代表控制器提供的觸覺回饋硬體。

您可能還會遇到另一件事,視瀏覽器和遊戲手把而定 是 vibrationActuator 屬性。這種環狀效果有兩種:

  • 雙重拍:由兩個奇異旋轉的質感反應器產生的觸覺回饋效應,分別用於遊戲手把的每一次推桿。
  • 火箭:響起:由兩個獨立馬達產生的觸覺回饋效果,在各個遊戲手把的觸發板上,有一個馬達。

下方為示意圖 顯示按鈕和軸在一般遊戲手台上的對應和排列方式。

常見遊戲手把的按鈕和軸對應圖譜總覽。
標準遊戲手把版面配置的示意圖 (來源)。

遊戲手把連線時的通知

如要瞭解遊戲手把連線的時間,請監聽要在遊戲畫面上觸發的 gamepadconnected 事件 window 物件。當使用者透過 USB 或藍牙連線至遊戲手把時, 會觸發 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 事件。請留意以下範例 我拔除 Xbox 360 控制器時,connected 現在是 false

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 中的陣列「一律」設有四個固定長度為 4 個項目。如果是 0 或以下 超過四個遊戲手把,則一個項目可能只有 null。請務必檢查 請注意,遊戲板會「記住」而且不一定隨時出現在 第一個可用的版位

// 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-umble 描述觸覺技術與 一般遊戲手把的每個控點都有奇異旋轉的大規模振動馬達。在這個設定中 是任何馬達都能震動整個遊戲手把這兩個質量不等於 結合這兩種特效,即可創造出更複雜的觸覺回饋。雙層影響 定義如下:

  • duration:設定震動效果的時間長度 (以毫秒為單位)。
  • startDelay:設定開始震動前的延遲時間。
  • strongMagnitudeweakMagnitude:設定震動強度和震動強度 較輕微旋轉的質心馬達,此範圍正規化為 0.01.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(),也不會 並觸發 gamepadconnectedgamepaddisconnected 事件。

<iframe src="index.html" allow="gamepad"></iframe>

示範

以下範例嵌入了 Gamepad 測試人員示範。原始碼 可以在 Glitch 上使用。將 遊戲搖桿使用 USB 或藍牙,並按下任何按鈕或移動任何軸。

額外步驟:前往 web.dev 玩 Chrome 恐龍遊戲

您可以使用遊戲手把玩 Chrome 恐龍遊戲 而非網站您可以在 GitHub 取得原始碼。 查看以下程式碼中的遊戲手把輪詢實作情形: trex-runner.js敬上 並留意它如何模擬按鍵操作

如要讓 Chrome 恐龍遊戲手把試用版正常運作, 從核心 Chromium 專案中淘汰 Chrome 恐龍遊戲 (更新 稍早的努力Arnelle Ballane 放在獨立網站上, 現有遊戲手把 API 實作項目,包括加入 DPI 和震動效果,以及建立全螢幕 模式,Mehul Satardekar 還提供深色模式 。盡情享受遊戲樂趣!

特別銘謝

這份文件已由 François Beaufort 審核 Joe Medley。Gamepad API 規格是由編輯者所編輯 Steve AgostonJames HollyerMatt Reynolds。舊版規格編輯器 Brandon JonesScott GrahamTed Mielczarek。Gamepad Extensions 規格是由 Brandon Jones。主頁橫幅由 Laura Torrent Puig 提供。