Chơi trò chơi khủng long trên Chrome bằng tay điều khiển trò chơi

Tìm hiểu cách sử dụng Gamepad API để đưa trò chơi của bạn trên web lên một tầm cao mới.

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ố được đưa ra nhằm mang lại hiệu quả kịch tính). Nếu bạn nhấn phím cách hoặc trên thiết bị di động thiết bị, nhấn vào khủng long, trang ngoại tuyến sẽ trở thành một trò chơi arcade có thể chơi. Có thể bạn sẽ 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 điều hướng vào about://dino hoặc, nếu bạn là người đam mê công nghệ, hãy duyệt tới about://network-error/-106. Nhưng bạn có biết có 270 triệu trò chơi khủng long trên Chrome được chơi mỗi tháng?

Trang ngoại tuyến của Chrome với trò chơi khủng long trên Chrome.
Nhấn phím cách để chơi!

Một sự thật khác được cho là sẽ hữu ích hơn nên biết nhưng có thể bạn chưa biết là trong trong chế độ arcade, bạn có thể chơi trò chơi bằng tay điều khiển trò chơi. Chúng tôi đã thêm dịch vụ hỗ trợ tay điều khiển trò chơi vào khoảng một năm trước vào thời điểm viết bài này bằng cam kết bởi Reilly Grant. Như bạn có thể thấy, trò chơi, giống như phần còn lại của Dự án Chromium đã hoàn tất nguồn mở. Trong tôi muốn hướng dẫn bạn cách sử dụng Gamepad API.

Sử dụng Gamepad API (API Tay điều khiển trò chơi)

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 toàn cầu trên cả hai nền tảng máy tính để bàn và thiết bị di động. Bạn có thể kiểm tra 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 đại diện cho một tay điều khiển trò chơi

Trình duyệt đại diện cho bàn chơi trò chơi là 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 phong cách của tay điều khiển trò chơi đã kết nối.
  • displayId: VRDisplay.displayId của một liên kết VRDisplay (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 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 điều khiển đang được hoặc có nhiều khả năng được cầm nhất trong năm
  • timestamp: Lần cập nhật dữ liệu gần đây nhất của tay điều khiển trò chơi này.
  • mapping: Nút và trục đang được sử dụng cho thiết bị này, có thể là "standard" hoặc "xr-standard".
  • pose: Đối tượng GamepadPose biểu thị thông tin về 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 thành phạm vi -1.01.0.
  • buttons: Một loạt trạng thái nút cho tất cả các nút trên tay điều khiển trò chơi.

Xin lưu ý rằng các nút có thể ở dạng kỹ thuật số (nhấn hoặc không nhấn) hoặc dạng analog (ví dụ: nhấn 78%). Chiến dịch nà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 được nhấn và false nếu không được nhấn.
  • touched: Trạng thái nhấn của nút. Nếu nút này có thể phát hiện thao tác chạm, thì là true nếu bạn nhấn vào nút và nếu không thì là false.
  • value: Đối với các nút có cảm biến analog, thuộc tính này thể hiện lượng đã nhấn nút, chuẩn hoá tuyến tính thành phạm vi từ 0.0 đến 1.0.
  • hapticActuators: Một mảng chứa GamepadHapticActuator mà mỗi đối tượng đại diện cho phần cứng phản hồi xúc giác có trên bộ đ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 bạn có, là một thuộc tính vibrationActuator. Công cụ này cho phép hai loại hiệu ứng tiếng ồn ào:

  • Dual-Rumble: Hiệu ứng phản hồi xúc giác do 2 bộ truyền động khối xoay lệch tâm tạo ra, mỗi bộ phận trên một tay cầm điều khiển trò chơi.
  • Trigger-Rumble: Hiệu ứng phản hồi xúc giác do hai động cơ độc lập tạo ra, với một động cơ nằm ở mỗi bộ kích hoạt của tay điều khiển trò chơi.

Tổng quan sơ đồ sau đây, được lấy theo thông số kỹ thuật, cho thấy sơ đồ ánh xạ cũng như cách sắp xếp các nút và trục trên một tay điều khiển trò chơi chung.

Sơ đồ tổng quan về ánh xạ các nút và trục của một tay điều khiển trò chơi phổ biến.
Hình ảnh minh hoạ một bố cục tay điều khiển trò chơi tiêu chuẩn (Nguồn).

Thông báo khi tay điều khiển trò chơi được kết nối

Để tìm hiểu khi nào tay điều khiển trò chơi được kết nối, hãy theo dõi sự kiện gamepadconnected sẽ kích hoạt trên Đối tượng window. Khi người dùng kết nối một tay điều khiển trò chơi, có thể là qua USB hoặc qua Bluetooth, GamepadEvent được kích hoạt có thông tin chi tiết về tay điều khiển trò chơi trong một thuộc tính gamepad có tên thích hợp. Trong phần sau đây, bạn có thể xem ví dụ về tay điều khiển Xbox 360 mà tôi đang sử dụng (vâng, tôi thích trò chơi xưa 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 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 diễn ra tương tự như cách phát hiện kết nối. Lần này, ứng dụng theo dõi sự kiện gamepaddisconnected. Lưu ý cách thực hiện trong ví dụ sau connected hiện là false khi tôi rút bộ điều khiển Xbox 360 ra khỏi nguồn điện.

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 bắt tay vào một tay điều khiển trò chơi sẽ bắt đầu bằng một lệnh gọi đến navigator.getGamepads(). Lệnh gọi này trả về một mảng với Gamepad mục. Mảng trong Chrome luôn có độ dài cố định là 4 mục. Nếu từ 0 trở xuống nhiều hơn 4 bàn chơi được kết nối, một mục có thể chỉ là null. Luôn đảm bảo kiểm tra tất cả các mục của mảng và lưu ý rằng các tay điều khiển trò chơi "nhớ" vị trí của họ và có thể không phải lúc nào cũng có mặt vị trí còn trống đầu tiên.

// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]

Nếu một hoặc nhiều bàn chơi được kết nối, nhưng navigator.getGamepads() vẫn báo cáo null mục, 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 nút bất kỳ trên tay điều khiển trò chơi đó. Sau đó, bạn có thể thăm dò tay điều khiển trò chơi trạng thái trong vòng lặp trò chơi như minh hoạ 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 một đối tượng cấu hình của động cơ hoặc các bộ truyền động khác có thể tác dụng một lực nhằm mục đích phản hồi xúc giác ý kiến phản hồi. Bạn có thể phát hiệu ứng xúc giác bằng cách gọi Gamepad.vibrationActuator.playEffect(). Chỉ loại hiệu ứng hợp lệ là 'dual-rumble''trigger-rumble'.

Hiệu ứng tiếng ầm ầm đượ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.
}

Tiếng gầm kép

Dual-rumble mô tả cấu hình xúc giác với động cơ rung khối lượng xoay lệch tâm trong mỗi tay cầm của một 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 trò chơi. Hai khối lượng không bằng nhau nên kết hợp hiệu ứng của từng thành phần để tạo ra hiệu ứng xúc giác phức tạp hơn. Hiệu ứng âm thanh kép được xác định bởi 4 tham số:

  • duration: Đặt thời lượng của hiệu ứng rung tính bằng mili giây.
  • startDelay: Đặt khoảng thời gian trễ cho đến khi chế độ rung bắt đầu.
  • strongMagnitudeweakMagnitude: Đặt mức cường độ rung cho các mức độ rung cao hơn và động cơ khối lượng xoay lệch tâm nhẹ hơn, được chuẩn hoá ở phạm vi 0.01.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,
  });
};

Bật tiếng ầm ầm

Tiếng rầm của trình kích hoạt là hiệu ứng phản hồi xúc giác do hai động cơ độc lập tạo ra, với một động cơ nằm ở mỗi nút kích hoạt 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ố Gamepad API xác định tính năng kiểm soát bằng chính sách được xác định bằng chuỗi "gamepad". Giá trị mặc định của allowlist"self". Chính sách về quyền của tài liệu xác định liệu bất kỳ nội dung nào trong tài liệu đó có được phép truy cập navigator.getGamepads() hay không. Nếu bị tắt trong mọi tài liệu, không nội dung nào trong tài liệu sẽ được phép sử dụng navigator.getGamepads(), cũng như các sự kiện gamepadconnectedgamepaddisconnected sẽ kích hoạt.

<iframe src="index.html" allow="gamepad"></iframe>

Bản minh hoạ

Trong ví dụ sau đây, chúng tôi nhúng một bản minh hoạ người kiểm thử tay điều khiển trò chơi. Mã nguồn có trên Glitch. Thử bản minh hoạ bằng cách kết nối tay điều khiển trò chơi sử dụng USB hoặc Bluetooth và nhấn bất kỳ nút nào của tay điều khiển trò chơi hoặc di chuyển trục bất kỳ của tay điều khiển trò chơi đó.

Tiề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ò chơi trên thiết bị này rất trang web. Mã nguồn có trên GitHub. Hãy xem cách triển khai việc thăm dò ý kiến trên 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 có đã 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 sớm hơn Arnelle Ballane), đặt tác phẩm này trên một trang web độc lập, triển khai API tay điều khiển trò chơi hiện có bằng cách thêm hiệu ứng giảm âm thanh và rung, tạo ra chế độ toàn màn hình và Mehul Satardekar đã đóng góp một chế độ tối trong quá trình triển khai. Chúc bạn chơi vui vẻ!

Xác nhận

Tài liệu này đã được François Beaufort xem xét và Joe Medley. Thông số kỹ thuật của Gamepad API được chỉnh sửa bởi Steve Agoston thân mến! James HollyerMatt Reynolds. Những người chỉnh sửa thông số kỹ thuật trước đây Brandon Jones, Scott GrahamTed Mielczarek. Thông số kỹ thuật của Tiện ích Gamepad được chỉnh sửa bởi Brandon Jones. Hình ảnh chính của Laura Torrent Puig.