LibGDX输入模块之手柄控制器
我们一直在为游戏手柄和操纵杆添加新的扩展.最终呈现给你们的是gdx-controllers,我们的第一个扩展是每个平台有不同的后端实现(其他扩展通常只是交叉编译的JNI包装器,在每个平台上使用相同的Java代码)。
此扩展的目标是提供以下功能:
- 枚举连接的控制器
- 支持每个控制器的按钮,轴,滑块,POV和加速度计
- 在全局或每个控制器上监听控制器事件
- 控制器状态轮询
我们尽量保持API尽可能的小,有可能将来继续扩展,并且无需初始化,底层后端将自动初始化它。
枚举控制器
一个或多个控制器可能连接到您的PC /设备。 Controllers类具有查询当前连接的设备的方法:
for (Controller controller : Controllers.getControllers()) {
Gdx.app.log(TAG, controller.getName());
}
Controller #getControllers()返回的Array中的控制器的顺序通常是控制器连接的顺序。 但是你不应该过分依靠这个顺序。 请参阅下面的(dis-)connecting 设备部分。
必须在渲染线程上执行Controllers类的所有方法,即ApplicationListener的任何方法。
轮询设备状态
一旦你有一个Controller实例,你可以查询它的当前状态,控制器可以有不同的组件:
- 按钮: 这包括您通常使用额X,Y按钮以及某些控制器上的D-PAD,按钮可以按下一些释放。
- 轴:通常由模拟棒提供,值在1和-1之间。
- POV(又名帽子开关):提供离散的定向状态,例如 北,东,西,东南等。
- 滑块和加速度计:这些都在API中,但目前未经测试。
一个经典的控制器示例是XBox 360控制器:
It has a left and a right analogue stick, each with an x- and a y-axis, triggers on the back, each representing a single axis and various buttons and a d-pad, which might either be reported as buttons or as axes.
轮询特定组件的状态非常简单:
boolean buttonPressed = controller.getButton(buttonCode);
float axisValue = controller.getAxis(axisCode);
...
每个组件都有自己的代码(类似于keyboad键的键代码或扫描代码)。 该代码是控制器特定的,例如 XBox控制器上的X按钮可能具有与PS3控制器上的X按钮不同的代码。 稍后我们再回到这个问题。
基于事件的控制器输入
当轮询控制器时,可能会丢失一些输入事件。 对于某些任务,基于事件的输入也比基于轮询的输入更合适。 因此,我们为您提供一种注册监听器来接收控制器事件的方式,您必须实现监听控制器事件的接口称为ControllerListener:
public interface ControllerListener {
public void connected(Controller controller);
public void disconnected(Controller controller);
public boolean buttonDown (Controller controller, int buttonCode);
public boolean buttonUp (Controller controller, int buttonCode);
public boolean axisMoved (Controller controller, int axisCode, float value);
public boolean povMoved (Controller controller, int povCode, PovDirection value);
public boolean xSliderMoved (Controller controller, int sliderCode, boolean value);
public boolean ySliderMoved (Controller controller, int sliderCode, boolean value);
public boolean accelerometerMoved (Controller controller, int accelerometerCode, Vector3 value);
}
前两个方法主要是控制器在连接或者断开连接时会调用。
接下来的两个方法报告按钮被按下或释放的事件。
当轴值发生更改时,调用axisMoved()方法。以此类推.
ControllerListener可以被添加到控制器,在这种情况下,它将监听来自所有控制器的事件,也可以侦听特定的控制器,在这种情况下,它只会从该控制器接收事件:
Controllers.addListener(listener); // receives events from all controllers
controller.addListener(listener); // receives events only from this controller
如果你不想实现所有这些方法,而只是关心其中少数的几个方法,你可以继承ControllerAdapter:
controller.addListener(new ControllerAdapter() {
@Override
public void connected(Controller controller) {
...
}
public void disconnected(Controller controller) {
...
}
};
您可能已经注意到一些侦听器方法返回一个布尔值。 如果在全局或者特定的控制器注册了多个监听器,则会使用此选项,如果这样的方法返回false,那么事件将被传递给下一个监听器。 如果该方法返回true,则该事件将不再传播。
所有侦听器方法都将在渲染线程上被调用,就像普通的InputProcessor一样。
映射和代码
如上所述,不同的组件具有不同的代码。 这些代码没有标准化,所以我们在处理控制器时有两个选择:
- 硬编码特定控制器的代码,例如 Ouya控制器
- 让玩家配置控制器绑定,例如 运行每个动作,并要求玩家按相应的控制器组件(按钮,轴,POV等)。
我们目前拥有Ouya控制器按钮和轴的代码。 要检查控制器是否是Ouya控制器,可以这样做:
if(controller.getName().equals(Ouya.ID)) {
// we know it's an Ouya controller, so we can use the Ouya codes
float leftXAxis = controller.getAxis(Ouya.AXIS_LEFT_X);
boolean oButton = controller.getButton(Ouya.BUTTON_O);
}
您还可以检查您是否正在Ouya设备上运行:
if(Ouya.runningOnOuya) {
// DO SOMETHING!
}
您也可以将Ouya控制器与普通Android设备配对,这就是为什么要判断是否在Ouya设备上运行的原因。
我们将来会为流行的控制器添加更多的映射,例如 Xbox 360和PS3控制器。
请注意,根据操作系统,这些代码对于同一类型的控制器可能不同。 我的便宜的Logitech控制器在Windows上为x轴指定了代码0,在Linux和Mac OS X上获得了代码1。你可以在com.badlogic.gdx.controllers.mappings包中找到对应的映射和代码,如上面的Ouya类, 我们将确保代码适用于所有操作系统。
最后,最好让用户决定如何使用她的手柄。 编写一个简单的配置对话框,通过操作运行,并要求用户按下一个按钮很容易做到。 然后您可以将这些映射与控制器名称一起保存到文件中并重新加载这些配置项。
控制器连接与断开
目前在桌面和Android上都报告了控制器的连接与断开。 如果您的游戏支持游戏手柄,请确保处理设备断开与连接! 例如如果控制器在游戏过程中断开连接,则暂停游戏,并要求用户重新连接控制器。 请注意,在这种情况下,您将获得一个全新的Controller实例,因此请确保正确连接任何监听器。 旧的控制器实例将被报告为断开连接。
融入您的项目
在gdx-setup app中勾选Controllers选项,对于LWJGL 3,替换gdx-controllers-desktop依赖 更改为:gdx-controllers-lwjgl3,在桌面应用中,移除compile "com.badlogicgames.gdx:gdx-controllers-platform:$gdxVersion:natives-desktop" 依赖.
Tests & Demos
我写了一个新的小测试,可以显示当前连接的控制器和事件数据,称为ControllersTest。 我还增加了gdx-invaders 演示来支持Ouya控制器。 请注意,该Demo不会处理断开连接或提供任何配置选项。