Tìm hiểu cách sử dụng Gamepad API để nâng tầm trò chơi trên web của bạn.
Trứng phục sinh trên trang ngoại tuyến của Chrome là một trong những bí mật được giữ kín nhất trong lịch sử ([citation needed]
, nhưng tuyên bố này được đưa ra để tạo hiệu ứng ấn tượng). Nếu bạn nhấn phím dấu cách hoặc nhấn vào hình khủng long trên thiết bị di động, trang ngoại tuyến sẽ trở thành một trò chơi điện tử có thể chơi được. Bạn có thể biết rằng
bạn không thực sự phải chuyển sang chế độ ngoại tuyến khi muốn chơi: trong Chrome, bạn chỉ cần chuyển đến
about://dino
hoặc nếu là người đam mê công nghệ, hãy duyệt đến about://network-error/-106
. Nhưng bạn có biết rằng có 270 triệu người chơi trò chơi khủng long trên Chrome mỗi tháng không?
Một thực tế khác có thể hữu ích hơn mà bạn có thể chưa biết là ở chế độ trò chơi điện tử, bạn có thể chơi trò chơi bằng tay điều khiển trò chơi. Tính năng hỗ trợ tay điều khiển trò chơi được thêm vào khoảng một năm trước, tại thời điểm viết bài này trong một commit của Reilly Grant. Như bạn có thể thấy, trò chơi này, giống như phần còn lại của dự án Chromium, hoàn toàn là nguồn mở. Trong bài đăng này, tôi muốn hướng dẫn bạn cách sử dụng API Tay điều khiển trò chơi.
Sử dụng Gamepad API
Phát hiện tính năng và hỗ trợ trình duyệt
Gamepad API có khả năng hỗ trợ trình duyệt tuyệt vời trên cả máy tính và thiết bị di động. Bạn có thể phát hiện xem Gamepad API có được hỗ trợ hay không bằng cách sử dụng đoạn mã sau:
if ('getGamepads' in navigator) {
// The API is supported!
}
Cách trình duyệt biểu thị tay điều khiển trò chơi
Trình duyệt biểu thị tay điều khiển dưới dạng đối tượng Gamepad
. Gamepad
có các thuộc tính sau:
id
: Chuỗi nhận dạng cho tay điều khiển. Chuỗi này xác định thương hiệu hoặc kiểu thiết bị tay điều khiển trò chơi đã kết nối.displayId
:VRDisplay.displayId
củaVRDisplay
được liên kết (nếu có liên quan).index
: Chỉ mục của tay điều khiển trong trình điều hướng.connected
: Cho biết tay điều khiển có còn kết nối với hệ thống hay không.hand
: Một enum xác định tay đang cầm tay điều khiển hoặc nhiều khả năng sẽ được cầm.timestamp
: Lần gần nhất cập nhật dữ liệu cho tay điều khiển này.mapping
: Bản đồ nút và trục đang được sử dụng cho thiết bị này,"standard"
hoặc"xr-standard"
.pose
: Đối tượngGamepadPose
đại diện cho thông tin về tư thế liên kết với tay điều khiển WebVR.axes
: Một mảng các giá trị cho tất cả trục của tay điều khiển, được chuẩn hoá tuyến tính theo phạm vi-1.0
–1.0
.buttons
: Một mảng trạng thái nút cho tất cả các nút của tay điều khiển.
Xin lưu ý rằng nút có thể là dạng kỹ thuật số (đã nhấn hoặc chưa nhấn) hoặc dạng tương tự (ví dụ: đã nhấn 78%). Đây là lý do các nút được báo cáo dưới dạng đối tượng GamepadButton
, với các thuộc tính sau:
pressed
: Trạng thái nhấn của nút (true
nếu nút được nhấn vàfalse
nếu không được nhấn.touched
: Trạng thái chạm của nút. Nếu nút có thể phát hiện thao tác chạm, thì thuộc tính này sẽ làtrue
nếu nút đang được chạm vàfalse
nếu không.value
: Đối với các nút có cảm biến tương tự, thuộc tính này biểu thị lượng nút đã được nhấn, được chuẩn hoá tuyến tính trong phạm vi0.0
–1.0
.hapticActuators
: Một mảng chứa các đối tượngGamepadHapticActuator
, mỗi đối tượng đại diện cho phần cứng phản hồi xúc giác có trên tay điều khiển.
Một điều khác mà bạn có thể gặp phải, tuỳ thuộc vào trình duyệt và tay điều khiển trò chơi mà bạn có, đó là thuộc tính vibrationActuator
. API này cho phép hai loại hiệu ứng rung:
- Dual-Rumble: Hiệu ứng phản hồi xúc giác do hai bộ truyền động khối lượng xoay lệch tâm tạo ra, mỗi bộ truyền động ở một tay cầm của tay điều khiển.
- Trigger-Rumble: Hiệu ứng phản hồi xúc giác do hai động cơ độc lập tạo ra, trong đó mỗi động cơ nằm trong một nút kích hoạt của tay điều khiển.
Bảng tổng quan sơ đồ sau đây, được lấy trực tiếp từ thông số kỹ thuật, cho thấy mối liên kết và cách sắp xếp các nút và trục trên tay điều khiển chung.
Thông báo khi tay điều khiển trò chơi được kết nối
Để tìm hiểu thời điểm tay điều khiển được kết nối, hãy theo dõi sự kiện gamepadconnected
kích hoạt trên đối tượng window
. Khi người dùng kết nối tay điều khiển (có thể xảy ra bằng USB hoặc Bluetooth), GamepadEvent
sẽ được kích hoạt và có thông tin chi tiết về tay điều khiển trong thuộc tính gamepad
được đặt tên phù hợp.
Trong phần sau, bạn có thể xem ví dụ về tay điều khiển Xbox 360 mà tôi có (vâng, tôi thích chơi trò chơi hoài cổ).
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"}
*/
});
Thông báo khi tay điều khiển bị ngắt kết nối
Việc nhận thông báo về việc ngắt kết nối tay điều khiển cũng tương tự như cách phát hiện kết nối.
Lần này, ứng dụng sẽ theo dõi sự kiện gamepaddisconnected
. Lưu ý cách trong ví dụ sau, connected
hiện là false
khi tôi rút phích cắm tay điều khiển 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
*/
});
Tay điều khiển trò chơi trong vòng lặp trò chơi
Việc sử dụng tay điều khiển bắt đầu bằng lệnh gọi đến navigator.getGamepads()
. Lệnh gọi này sẽ trả về một mảng có các mục Gamepad
. Mảng trong Chrome luôn có độ dài cố định là 4 mục. Nếu không có hoặc có ít hơn 4 tay điều khiển trò chơi được kết nối, thì một mục có thể chỉ là null
. Luôn nhớ kiểm tra tất cả các mục của آرایه và lưu ý rằng tay điều khiển trò chơi "ghi nhớ" vị trí của chúng và không phải lúc nào cũng xuất hiện ở vị trí đầu tiên có sẵn.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Nếu một hoặc nhiều tay điều khiển trò chơi được kết nối nhưng navigator.getGamepads()
vẫn báo cáo các mục null
, bạn có thể cần phải "đánh thức" từng tay điều khiển trò chơi bằng cách nhấn bất kỳ nút nào trên tay điều khiển đó. Sau đó, bạn có thể thăm dò trạng thái tay điều khiển trong vòng lặp trò chơi như trong mã sau.
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();
Bộ truyền động rung
Thuộc tính vibrationActuator
trả về một đối tượng GamepadHapticActuator
, tương ứng với cấu hình của động cơ hoặc các bộ truyền động khác có thể áp dụng lực cho mục đích phản hồi xúc giác. Bạn có thể phát hiệu ứng xúc giác bằng cách gọi Gamepad.vibrationActuator.playEffect()
. Các loại hiệu ứng hợp lệ duy nhất là 'dual-rumble'
và 'trigger-rumble'
.
Hiệu ứng rung được hỗ trợ
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.
}
Rung kép
Chế độ rung kép mô tả một cấu hình xúc giác với một động cơ rung khối lượng xoay lệch tâm trong mỗi tay cầm của tay điều khiển trò chơi tiêu chuẩn. Trong cấu hình này, một trong hai động cơ có thể rung toàn bộ tay điều khiển. Hai khối lượng này không bằng nhau để có thể kết hợp hiệu ứng của từng khối lượng nhằm tạo ra hiệu ứng xúc giác phức tạp hơn. Hiệu ứng rung kép được xác định bằng 4 tham số:
duration
: Đặt thời lượng của hiệu ứng rung tính bằng mili giây.startDelay
: Đặt thời lượng của độ trễ cho đến khi bắt đầu rung.strongMagnitude
vàweakMagnitude
: Thiết lập mức độ rung cho các động cơ khối lượng quay lệch tâm nặng hơn và nhẹ hơn, được chuẩn hoá theo phạm vi0.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,
});
};
Kích hoạt chế độ rung
Rung cò là hiệu ứng phản hồi xúc giác do hai động cơ độc lập tạo ra, trong đó mỗi động cơ nằm trong một cò của tay điều khiển.
// 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,
});
};
Tích hợp với Chính sách về quyền
Quy cách API tay điều khiển trò chơi xác định một tính năng do chính sách kiểm soát được xác định bằng chuỗi "gamepad"
. allowlist
mặc định là "self"
. Chính sách quyền của tài liệu xác định xem có nội dung nào trong tài liệu đó được phép truy cập vào navigator.getGamepads()
hay không. Nếu bị tắt trong bất kỳ tài liệu nào, thì không có nội dung nào trong tài liệu được phép sử dụng navigator.getGamepads()
, cũng như các sự kiện gamepadconnected
và gamepaddisconnected
sẽ không kích hoạt.
<iframe src="index.html" allow="gamepad"></iframe>
Bản minh hoạ
Bản minh hoạ trình kiểm thử tay điều khiển trò chơi được nhúng trong ví dụ sau. Bạn có thể tìm thấy mã nguồn trên Glitch. Hãy thử bản minh hoạ bằng cách kết nối tay điều khiển bằng USB hoặc Bluetooth và nhấn bất kỳ nút nào hoặc di chuyển bất kỳ trục nào của tay điều khiển.
Phần thưởng: chơi trò chơi khủng long trên Chrome trên web.dev
Bạn có thể chơi Trò chơi khủng long trên Chrome bằng tay điều khiển trên chính trang web này. Bạn có thể xem mã nguồn trên GitHub.
Hãy xem cách triển khai tính năng thăm dò ý kiến của tay điều khiển trong trex-runner.js
và lưu ý cách tính năng này mô phỏng các thao tác nhấn phím.
Để bản minh hoạ tay điều khiển trò chơi khủng long trên Chrome hoạt động, tôi đã tách trò chơi khủng long trên Chrome khỏi dự án Chromium cốt lõi (cập nhật nỗ lực trước đó của Arnelle Ballane), đặt trò chơi này trên một trang web độc lập, mở rộng việc triển khai API tay điều khiển hiện có bằng cách thêm hiệu ứng cúi đầu và rung, tạo chế độ toàn màn hình và Mehul Satardekar đã đóng góp vào việc triển khai chế độ tối. Chúc bạn chơi vui vẻ!
Đường liên kết hữu ích
- Thông số kỹ thuật của Gamepad API
- Thông số kỹ thuật của tiện ích API tay điều khiển
- Kho lưu trữ GitHub
Lời cảm ơn
Tài liệu này đã được François Beaufort và Joe Medley xem xét. Thông số kỹ thuật của API Tay điều khiển trò chơi do Steve Agoston, James Hollyer và Matt Reynolds biên tập. Các biên tập viên thông số kỹ thuật trước đây là Brandon Jones, Scott Graham và Ted Mielczarek. Thông số kỹ thuật của Tiện ích tay điều khiển trò chơi do Brandon Jones chỉnh sửa. Hình ảnh chính của Laura Torrent Puig.