瞭解如何使用 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
: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 中的陣列「一律」固定包含四個項目。如果連結零或少於 4 個遊戲搖桿,項目可能只有 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 完成更早的努力)、將遊戲架上的 API 實作整合至獨立網站、加入專為遊戲控制器提供的 API 實作項目,以及建立全螢幕模式,以及 Mehul Sadetar 模式。盡情享受遊戲樂趣!
實用連結
特別銘謝
這份文件由 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。