游戏手柄 API

从小我就对电子游戏非常着迷。从 Atari 和 Colecovision 到 NES 和 Super NES,我花费了无数个小时玩各种各样的游戏。虽然我自己的电子游戏玩的时间减少了,但我仍然对游戏领域的问题和进步感兴趣。我见证了网络游戏的近来爆火,并且坚信这将开启一个新的游戏时代,为广大受众提供海量的游戏。然而,在探索蓬勃发展的网络游戏场景时,我注意到了一件事——许多游戏如果能用游戏手柄玩会更有趣!我着手通过为 Firefox 实现一些功能来解决这个问题,于是游戏手柄 API 诞生了。

A collection of game controllers

启用 API

从 Firefox 24 开始,游戏手柄 API 在一个首选项后面可用。您可以通过加载 about:config 并将 dom.gamepad.enabled 首选项设置为 true 来启用它。Firefox 的 Nightly 和 Aurora 版本默认启用了该 API。我们预计将在 Firefox 28 中以类似的方式启用发布版本。

使用 API

游戏手柄 API 的设计非常简单。规范有意地只尝试描述一个用于处理传统游戏手柄的接口——一组按钮和轴。我们认为这涵盖了大多数现有的游戏控制器,同时避免了尝试指定一个涵盖所有内容的 API 的复杂性。该 API 包含一个函数调用、一些 DOM 事件和一个要使用的对象类型。

获取游戏手柄

在实现中,除非用户在页面可见时与游戏手柄交互,否则游戏手柄不会公开给网页。这是出于隐私原因,主要是为了防止它们被用于指纹识别用户的系统。如果用户在页面可见时与(按下按钮、移动摇杆)控制器交互,则 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#the-gamepadconnected-event">gamepadconnected</a> 事件将被发送到页面。

<a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#gamepadevent-interface">GamepadEvent</a> 对象有一个 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-GamepadEvent-gamepad">gamepad</a> 属性,该属性描述了相关设备。在 Firefox 中,一旦一个游戏手柄已公开给页面,将任何其他游戏手柄连接到系统(通过插入 USB 游戏手柄或关联蓝牙游戏手柄)将立即将该设备公开给页面并发送 gamepadconnected 事件。

游戏手柄 API 还提供了一个函数——<a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#methods">navigator.getGamepads()</a>——它返回当前对网页可见的所有设备的列表。每个对页面可见的游戏手柄都以其 index 属性指定的列表中的位置返回。

注意:此代码片段将在 Firefox 28 nightly 版本中有效,但在较旧的版本中无效,因为最近修复的一个错误

如果游戏手柄断开连接——例如,拔掉插头——则 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#the-gamepaddisconnected-event">gamepaddisconnected</a> 事件将触发到页面。对 Gamepad 对象的所有剩余引用都将将其 connected 属性设置为 false

Gamepad 对象

Gamepad 对象 表示游戏控制器的状态。它有一些属性来描述控制器

id
包含有关控制器的某些信息的字符串。这不是严格指定的,但在 Firefox 中,它将包含由连字符 (-) 分隔的三部分信息:两个 4 位十六进制字符串,包含控制器的 USB 供应商和产品 ID,以及驱动程序提供的控制器名称。此信息旨在允许您查找设备上控件的映射,以及向用户显示有用的反馈。
index
一个整数,对于当前连接到系统的每个设备都是唯一的。这可以用来区分多个控制器。
connected
布尔值:如果控制器仍然连接,则为 true;如果控制器已断开连接,则为 false
mapping
一个字符串,指示浏览器是否已将设备上的控件重新映射到已知的布局。目前只支持一种已知的布局——“标准游戏手柄”。如果浏览器能够将设备上的控件映射到该布局,则 mapping 属性将设置为字符串 standard
axes
一个浮点值数组,包含设备上每个轴的状态。通常这些表示模拟摇杆,其中一对轴给出摇杆在其 X 和 Y 轴上的位置。每个轴都归一化为 -1.0..1.0 的范围,其中 -1.0 表示轴的最上或最左位置,1.0 表示轴的最下或最右位置。
buttons
一个 GamepadButton 对象 数组,包含设备上每个按钮的状态。每个 GamepadButton 都有一个 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-GamepadButton-pressed">pressed</a> 和一个 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-GamepadButton-value">value</a> 属性。pressed 属性是一个布尔值,指示按钮当前是否按下 (true) 或未按下 (false)。value 属性是一个浮点值,用于启用表示模拟按钮,例如许多现代游戏手柄上的触发器。这些值归一化为 0.0..1.0 的范围,其中 0.0 表示未按下的按钮,1.0 表示完全按下的按钮。

跨浏览器兼容性

游戏手柄 API 规范 在 Firefox 和 Chrome 中都实现了,但兼容性程度不同。目前,Firefox 实现了 编辑器草案 的全部内容,除了 Gamepad 对象上的 <a href="https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#widl-Gamepad-timestamp">timestamp</a> 属性。

在撰写本文时,Chrome 尚未实现 ongamepadconnectedongamepaddisconnected 事件。您必须使用 navigator.webkitGetGamepads() 函数(注意前缀)来访问游戏手柄。

另一个需要注意的区别是,在 Chrome 中,Gamepad 对象是快照,而在 Firefox 中,它们始终反映控制器的最新状态。这意味着对于 Chrome,您需要在每一帧中使用 navigator.webkitGetGamepads() 轮询游戏手柄集,而在 Firefox 中,您可以将对 Gamepad 对象的引用保存在变量中,并在以后引用它以检查当前状态。

最后,最近的规范更改意味着 Chrome 和 Firefox 的发布版本与 Firefox 28 有所不同——Gamepad 对象的 buttons 属性最初被指定为双精度数数组,而不是 GamepadButton 对象数组。这可以通过简单的类型检查安全地处理,如下面的代码示例所示。

一个简单的演示

我将为您提供一个简单的演示,它将这里的所有部分组合在一起,并展示了您如何在当今以跨浏览器的方式使用 API。它只是查找连接或断开连接的游戏手柄,并显示所有已知控制器的按钮和轴的当前状态。此演示应该在 Firefox 24 及更高版本以及 Chrome 21 及更高版本中运行。您可以在Github 上找到演示的源代码

我希望这篇博文能激励您重新思考在网络游戏领域可能实现的目标。让我们一起制作一些游戏吧!

A screenshot showing the Gamepad test page

关于 Robert Nyman [荣誉编辑]

Mozilla Hacks 的技术布道师和编辑。发表关于 HTML5、JavaScript 和开放网络的演讲和博客文章。Robert 是 HTML5 和开放网络的坚定支持者,自 1999 年以来一直从事 Web 前端开发工作——在瑞典和纽约市。他还定期在http://robertnyman.com 上发表博文,并且喜欢旅行和结识新朋友。

更多 Robert Nyman [荣誉编辑] 的文章……


17 条评论

  1. Dietrich Ayala

    看到这个实现真是太棒了。

    您能否链接一些您推荐与该 API 配合使用的游戏手柄型号?

    游戏手柄是否可以在各种操作系统上使用?

    Firefox OS 上是否已提供此功能?

    2013 年 12 月 19 日 10:20

    1. Ted Mielczarek

      大多数通用 USB 游戏手柄在任何平台上都可以正常使用。Xbox 360 控制器在任何地方都可以正常使用。PS3 控制器比较挑剔——在 Linux 上运行良好,在 OS X 上可能需要驱动程序,在 Windows 上运行效果不佳(有一个非官方驱动程序,但很糟糕)。帖子中的照片中那些古老的 USB 控制器在任何地方都可以正常使用。

      我们目前支持 Windows、OS X 和 Linux。在添加对 Android[1](目前无人拥有)和 Firefox OS[2] 的支持方面存在一些错误。Firefox OS 部分有点复杂,因为 Firefox OS 中的 HID 支持目前处于前沿状态,但肯定有人在关注这个问题。

      1. https://bugzilla.mozilla.org/show_bug.cgi?id=852935
      2. https://bugzilla.mozilla.org/show_bug.cgi?id=852945

      2013 年 12 月 19 日 13:46

      1. Jason Hutchinson

        BetterDS3 工具使 PS3 控制器在 Windows 上更容易使用。

        2013 年 12 月 23 日 09:15

  2. sole

    该演示与 Logitech Dual Action 控制器配合使用效果很好 ^_^

    2013 年 12 月 19 日 11:54

    1. Robert Nyman [编辑]

      不错!

      2013 年 12 月 20 日 09:08

  3. Hugo Habel

    这真是太棒了!我用 PS3 控制器试了一下演示,效果很好。现在我正在思考可以用这个 API 创建什么。

    2013 年 12 月 19 日 16:58

    1. Robert Nyman [编辑]

      谢谢,听起来不错!

      2013 年 12 月 20 日 09:07

  4. Šime Vidas

    这是我用 Logitech USB 游戏手柄玩演示的视频:https://twitter.com/simevidas/status/413899560734306304。我同意 Hugo 的观点。这太棒了 :-D

    2013 年 12 月 19 日 23:34

    1. Robert Nyman [编辑]

      非常酷!

      2013 年 12 月 20 日 09:08

  5. ilyas

    非常好!游戏手柄欢迎来到浏览器游戏世界!

    2013 年 12 月 20 日 00:21

    1. Robert Nyman [编辑]

      谢谢!

      2013 年 12 月 20 日 09:08

  6. Andy

    感谢各位发布这篇博文!自从 navigator.gamepads 出现以来,我一直在自定义游戏引擎中对其进行研究。

    我正在更新我的通用输入库,该库将键盘和游戏手柄输入抽象到一个通用接口,但使用 Firefox 27 时,我在将 Gamepad 对象用作原型时遇到了问题,例如

    a = navigator.getGamepads();
    b = Object.create(a[1]);
    console.log(b);
    console.log(b.buttons);

    这导致 Firebug 的控制台和对象检查器显示
    http://xhva.net/gamepad_error_1.png
    http://xhva.net/gamepad_error_2.png

    将 Gamepad 用作原型时是否无法访问其属性是故意的?

    2013 年 12 月 22 日 07:30

    1. Ted Mielczarek

      我不确定这是否应该可以工作,但我不是 DOM 专家。欢迎您提交错误报告,我可以获得一些专家的意见。

      2013 年 12 月 23 日 10:10

  7. thinsoldier

    演示与我的 Logitech Driving Force GT 方向盘完美配合。 :)

    2013 年 12 月 23 日 09:36

    1. Jaja

      轮子能用吗?这对我来说太神奇了:)

      我认为它可以用于非常有趣的应用程序

      2013年12月30日 23:58

      1. Ted Mielczarek

        我相信游戏方向盘应该可以正常工作,因为它们通常在系统中看起来就像游戏手柄设备。

        2013年12月31日 09:57

  8. Dread Knight

    使用USB连接测试了PS3手柄的演示版。运行完美,太棒了!

    2014年1月17日 13:12

本文评论已关闭。