瞭解如何使用 Gamepad API,讓網頁遊戲更上一層樓。
Chrome 的離線網頁彩蛋是史上最容易走漏風聲的秘密之一 ([citation needed]
,
但這只是為了戲劇效果)。按下空白鍵 (行動裝置上則輕觸恐龍),離線頁面就會變成可玩的街機遊戲。您可能知道,想玩遊戲時其實不必離線:在 Chrome 中,只要前往 about://dino
,或瀏覽 about://network-error/-106
,就能開始玩遊戲。但你知道嗎?每個月有 2.7 億人次玩 Chrome 恐龍遊戲!

您可能不知道,在街機模式中,您可以使用遊戲手把玩遊戲。大約一年前,在撰寫本文時,Reilly Grant 在提交中新增了遊戲手把支援功能。如您所見,這款遊戲與 Chromium 專案的其他部分一樣,完全開放原始碼。在這篇文章中,我將說明如何使用 Gamepad API。
使用 Gamepad API
功能偵測和瀏覽器支援
Gamepad API 在電腦和行動裝置上都支援瀏覽器,您可以使用下列程式碼片段,偵測系統是否支援 Gamepad API:
if ('getGamepads' in navigator) {
// The API is supported!
}
瀏覽器如何表示遊戲手把
瀏覽器會將遊戲手把表示為 Gamepad
物件。Gamepad
具有下列屬性:
id
:遊戲手把的識別字串。這個字串會識別所連線控制器的品牌或樣式。displayId
:相關聯VRDisplay
的VRDisplay.displayId
(如適用)。index
:導覽器中遊戲手把的索引。connected
:指出遊戲手把是否仍連線至系統。hand
:列舉,定義控制器握持的手,或最有可能握持的手。timestamp
:上次更新這款遊戲手把資料的時間。mapping
:裝置使用的按鈕和軸對應,可為"standard"
或"xr-standard"
。pose
:代表與 WebVR 控制器相關聯的姿勢資訊的GamepadPose
物件。axes
:遊戲手把所有軸的值陣列,線性正規化至-1.0
–1.0
範圍。buttons
:遊戲手把所有按鈕的按鈕狀態陣列。
請注意,按鈕可以是數位 (按下或未按下) 或類比 (例如按下 78%)。因此,按鈕會以 GamepadButton
物件的形式回報,並包含下列屬性:
pressed
:按鈕的按下狀態 (按鈕按下時為true
,未按下時為false
)。touched
:按鈕的觸控狀態。如果按鈕可以偵測觸控,則在按鈕遭到觸控時,這個屬性為true
,否則為false
。value
:如果是具有類比感應器的按鈕,這個屬性代表按鈕的按壓量,線性正規化至0.0
到1.0
的範圍。hapticActuators
:包含GamepadHapticActuator
物件的陣列,每個物件都代表控制器上可用的觸覺回饋硬體。
視瀏覽器和遊戲手把而定,您可能會遇到 vibrationActuator
屬性。可產生兩種震動效果:
- 雙重震動:由兩個偏心旋轉質量致動器產生的觸覺回饋效果,分別位於遊戲手把的握把中。
- 觸發器震動:由兩個獨立馬達產生的觸覺回饋效果,每個馬達分別位於遊戲手把的觸發器中。
下圖是規格中的示意圖,顯示一般遊戲手把上的按鈕和軸向對應關係和排列方式。
遊戲手把連線時的通知
如要瞭解遊戲手把何時連線,請監聽 window
物件上觸發的 gamepadconnected
事件。使用者連線遊戲手把時 (可透過 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 中的陣列一律有四個項目的固定長度。如果連線的遊戲手把少於四個,項目可能只會顯示 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.
}
雙震動
雙震動是指觸覺設定,在標準遊戲控制器的每個把手都設有偏心旋轉質量振動馬達。在此設定中,任一馬達都能震動整個遊戲手把。這兩個質量不相等,因此可以結合各自的效果,產生更複雜的觸覺效果。雙震動效果由四個參數定義:
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 或藍牙連線連接遊戲手把,然後按下任一按鈕或移動任一軸。
加碼:在 web.dev 上暢玩 Chrome 恐龍遊戲
你可以在這個網站上使用遊戲手把玩 Chrome 恐龍遊戲。原始碼位於 GitHub。請查看 trex-runner.js
中的遊戲手把輪詢實作項目,並注意其模擬按鍵的方式。
為了讓 Chrome 恐龍遊戲手把示範正常運作,我從核心 Chromium 專案中擷取了 Chrome 恐龍遊戲 (更新了 Arnelle Ballane 的早期成果),並將其放在獨立網站上,透過新增閃避和震動效果擴充現有的 Gamepad API 實作項目,建立全螢幕模式,Mehul Satardekar 則貢獻了深色模式實作項目。祝你玩得開心!
實用連結
特別銘謝
本文由 François Beaufort 和 Joe Medley 審查。Gamepad API 規格由 Steve Agoston、James Hollyer 和 Matt Reynolds 編輯。前規格編輯者為 Brandon Jones、Scott Graham 和 Ted Mielczarek。Gamepad 擴充功能規格由 Brandon Jones 編輯。主頁橫幅圖片由 Laura Torrent Puig 提供。