瞭解如何使用 Gamepad API,讓您的網路遊戲更上一層樓。
Chrome 的離線頁面彩蛋是歷史上最容易洩漏的秘密之一 ([citation needed]
,但這只是為了營造戲劇效果而說的話)。如果您按下 空格鍵,或是在行動裝置上輕觸恐龍圖示,離線頁面就會變成可玩的街機遊戲。您可能知道,想玩遊戲時不一定要離線:在 Chrome 中,您可以前往 about://dino
,或是前往 about://network-error/-106
。不過,你知道每個月有 2 億人次玩 Chrome 恐龍遊戲嗎?
另一個您可能不知道,但相當實用的事實是,您可以在街機模式中使用遊戲控制器玩遊戲。在撰寫本文時,遊戲控制器支援功能大約在一年多前加入,當時是 Reilly Grant 的提交。如您所見,這款遊戲與其他 Chromium 專案一樣,完全是開放原始碼。在本篇文章中,我將說明如何使用 Gamepad API。
使用 Gamepad API
功能偵測和瀏覽器支援
在電腦和行動裝置上,Gamepad API 都普遍支援瀏覽器。您可以使用以下程式碼片段偵測是否支援 Gamepad API:
if ('getGamepads' in navigator) {
// The API is supported!
}
瀏覽器如何呈現遊戲控制器
瀏覽器會以 Gamepad
物件表示遊戲搖桿。Gamepad
包含下列屬性:
id
:遊戲控制器的 ID 字串。這個字串會識別已連結的遊戲控制器裝置品牌或樣式。displayId
:相關聯VRDisplay
的VRDisplay.displayId
(如有)。index
:導覽器中的遊戲控制器索引。connected
:指出遊戲控制器是否仍連線至系統。hand
:列舉定義控制器目前握手或最有可能握在的手上。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
屬性。它支援兩種震動效果:
- 雙震動:由兩個偏心旋轉質量致動器產生的觸覺回饋效果,每個手把握把各有一個。
- 觸發震動:由兩個獨立馬達產生的觸覺回饋效果,每個遊戲控制器扳機鍵各有一個馬達。
下圖是直接從規格擷取的示意圖概覽,顯示一般遊戲控制器上的按鈕和軸的對應和排列方式。
遊戲手把連線時的通知
如要瞭解遊戲手把連線的時間,請監聽 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.
}
雙重震動
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,
});
};
觸發震動
觸發震動是指由兩個獨立馬達產生的觸覺回饋效果,每個遊戲控制器的觸發鍵中各有一個馬達。
// 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>
示範
以下範例嵌入了 Gamepad 測試人員示範。原始碼可在 Glitch 上取得。請使用 USB 或藍牙連接遊戲控制器,然後按下任何按鈕或移動任何軸,試試這個示範。
額外獎勵:在 web.dev 上玩 Chrome 恐龍遊戲
您可以在這個網站上使用遊戲控制器玩 Chrome 恐龍遊戲。原始碼可在 GitHub 取得。請查看 trex-runner.js
中的遊戲控制器輪詢實作項目,並注意它如何模擬按鍵按下動作。
為了讓 Chrome 恐龍遊戲搖桿示範能正常運作,我從核心 Chromium 專案中擷取 Chrome 恐龍遊戲 (更新 Arnelle Ballane 先前的努力),將其放置在獨立網站上,並透過新增靜音和震動效果來擴充現有的遊戲搖桿 API 實作,建立全螢幕模式,而 Mehul Satardekar 則提供了深色模式實作。盡情享受遊戲樂趣!
實用連結
特別銘謝
這份文件已由 François Beaufort 和 Joe Medley 審查。Gamepad API 規格是由 Steve Agoston、James Hollyer 和 Matt Reynolds 編輯,前規格編輯為 Brandon Jones、Scott Graham 和 Ted Mielczarek。Gamepad Extensions 規格是由 Brandon Jones 編輯。主頁橫幅由 Laura Torrent Puig 提供。