Tìm hiểu cách sử dụng Gamepad API để đưa trò chơi trên web của bạn lên một tầm cao mới.
Điều thú vị ẩn giấu 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. Có thể bạn đã biết rằng bạn không cần phải ngắt kết nối mạng khi muốn chơi trò chơi này: trong Chrome, bạn chỉ cần chuyển đến about://dino hoặc nếu là người am hiểu công nghệ, bạn có thể duyệt đến about://network-error/-106. Nhưng bạn có biết rằng
có đến
270 triệu lượt chơi trò chơi khủng long trên Chrome mỗi tháng?
Một thông tin khác có thể hữu ích hơn và bạn có thể chưa biết là ở chế độ arcade, 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ính đến thời điểm viết bài này) trong một cam kết của Reilly Grant. Như bạn thấy, trò chơi này, cũ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 Gamepad API.
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 rất tốt 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 trò chơi 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 trò chơi. Chuỗi này xác định thương hiệu hoặc kiểu của thiết bị tay điều khiển trò chơi đã kết nối.displayId:VRDisplay.displayIdcủaVRDisplayđược liên kết (nếu có liên quan).index: Chỉ mục của tay điều khiển trò chơi trong trình điều hướng.connected: Cho biết liệu tay điều khiển trò chơi có còn kết nối với hệ thống hay không.hand: Một enum xác định tay nào đang cầm bộ điều khiển hoặc có nhiều khả năng cầm bộ điều khiển nhất.timestamp: Lần gần nhất dữ liệu cho tay điều khiển trò chơi này được cập nhật.mapping: Ánh xạ 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 tư thế liên kết với bộ điều khiển WebVR.axes: Một mảng giá trị cho tất cả các trục của tay điều khiển trò chơi, được chuẩn hoá tuyến tính theo phạm vi từ-1.0đến1.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 trò chơi.
Xin lưu ý rằng các nút có thể là nút kỹ thuật số (được nhấn hoặc không được nhấn) hoặc nút analog (ví dụ: được nhấn 78%). Đây là lý do tại sao 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 được nhấn của nút (truenếu nút được nhấn vàfalsenếu nút không được nhấn.touched: Trạng thái được chạm của nút. Nếu nút có khả năng phát hiện thao tác chạm, thì thuộc tính này làtruenếu nút đang được chạm vàfalsenếu không.value: Đối với các nút có cảm biến analog, thuộc tính này thể hiện mức độ nhấn nút, được chuẩn hoá tuyến tính theo phạm vi từ0.0đến1.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 nữa 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 quay lệch tâm tạo ra, mỗi bộ nằm ở một bên tay cầm của tay điều khiển trò chơi.
- Rung cò: Hiệu ứng phản hồi xúc giác do hai động cơ độc lập tạo ra, mỗi động cơ nằm ở một cò của tay điều khiển trò chơi.
Thông tin tổng quan về sơ đồ sau đây, được lấy trực tiếp từ thông số kỹ thuật, cho thấy việc liên kết và sắp xếp các nút cũng như trục trên một tay điều khiển trò chơi chung.
Thông báo khi tay điều khiển trò chơi được kết nối
Để biết thời điểm tay điều khiển trò chơi đượ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 trò chơi (có thể qua USB hoặc Bluetooth),
một GamepadEvent sẽ được kích hoạt, trong đó có thông tin chi tiết về tay điều khiển trò chơi trong thuộc tính gamepad có tên phù hợp.
Sau đây, 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 cổ điển).
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 trò chơi 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 trò chơi 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. Hãy lưu ý cách connected hiện là false trong ví dụ sau khi tôi rút 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
Để lấy tay điều khiển trò chơi, hãy bắt đầu bằng lệnh gọi đến navigator.getGamepads(). Lệnh này sẽ trả về một mảng có Gamepad mục. 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 mảng và lưu ý rằng tay điều khiển trò chơi "nhớ" vị trí của chúng và có thể 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 null mục, thì 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 vào 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 của tay điều khiển trò chơi trong vòng lặp trò chơi như trong đoạn 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(). Chỉ có các loại hiệu ứng hợp lệ 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
Rung kép mô tả cấu hình xúc giác có động cơ rung khối lượng quay 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ỗi động cơ đều có khả năng làm rung toàn bộ tay điều khiển trò chơi. 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 gian trễ cho đến khi bắt đầu rung.strongMagnitudevàweakMagnitude: Đặt mức cường độ rung cho động cơ khối 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,
});
};
Rung nút kích hoạt
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 ở một cò của tay điều khiển trò chơi.
// 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
Thông số kỹ thuật của Gamepad API 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 về 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 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ể xem mã nguồn trên GitHub. Hãy thử bản minh hoạ bằng cách kết nối tay điều khiển trò chơi qua USB hoặc Bluetooth rồi nhấn vào 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.
Thưởng: Chơi trò chơi khủng long trên Chrome tại 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ò chơi ngay trên trang web này. Mã nguồn có trên GitHub.
Hãy xem cách triển khai thăm dò ý kiến về tay điều khiển trò chơi trong trex-runner.js và lưu ý cách mô phỏng 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 chính (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 cách triển khai API tay điều khiển trò chơi hiện có bằng cách thêm hiệu ứng cúi người và rung, tạo chế độ toàn màn hình và Mehul Satardekar đã đóng góp một cách triển khai chế độ tối. Chúc bạn chơi game vui vẻ!
Đường liên kết hữu ích
Xác nhậ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 Gamepad API 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.