在游戏开发或任何需要控制器支持的应用程序中,有多种选项可供选择。最简单的方法是使用一个提供XInput控制器访问的库。XInputium就是这样一个.NET库,它专注于XInput,旨在尽可能简化使用过程,同时提供强大的功能。本文将教如何使用XInputium将控制器支持集成到游戏或应用程序中。
什么是XInputium? XInputium是一个免费的开源.NET库,为应用程序提供对XInput兼容设备的访问。可以在GitHub上的XInputium仓库中看到它的演示应用程序(XInputium预览),它允许用户诊断XInput控制器并测试XInputium的一些特性。
XInputium与GitHub上的其他提供XInput功能的库有何不同?大多数提供XInput功能的库都是为游戏开发设计的,因此它们被调用在游戏循环内部,大部分输入处理留给。例如,它们允许获取控制器的当前状态,但如何处理这个状态取决于,需要编写自己的代码来检测按钮按下、按钮保持、摇杆移动等。
XInputium旨在解决这个问题。它的目标是让开发者编写更少的代码,让库处理大部分输入相关逻辑。例如,它允许检测特定的输入事件,比如当特定按钮保持一定时间,或者摇杆以特定速度在特定方向移动时。
XInputium还准备好在XAML应用程序中使用。它的属性可以绑定到XAML,使得将现成的XInput支持带入应用程序(而不仅仅是游戏)变得更加简单。
为了实现其目标,XInputium使用内部输入循环的概念来处理大部分输入。只需要在每个应用程序或游戏帧中从代码调用一个方法;这允许XInputium遍历其内部输入循环并提供时间测量的机会。内部输入循环使XInputium能够比较输入设备状态之间的输入,并提供基于事件的输入处理。它抽象了大部分常见的输入逻辑操作,尽管仍然可以使用更底层的方法。
如何开始使用XInputium? 假设已经有一个应用程序/游戏项目,需要允许用户使用XInput兼容控制器与应用程序/游戏交互。
首先,需要将XInputium NuGet包添加到项目中:
Install-Package XInputium
现在,让进入代码。从典型的“Hello world!”开始。以下示例在用户按下控制器上的任何按钮时,会在调试窗口中写入一条消息。显然,需要一个连接的XInput兼容控制器才能使这工作。
// 创建一个'XGamepad'实例,用于整个应用程序。
XGamepad gamepad = new XGamepad();
// 注册一个事件处理程序,仅用于测试。它在按钮被按下时触发。
gamepad.ButtonPressed += (s, e) => Debug.WriteLine($"Hello, universe! Button {e.Button} was pressed.");
// 在每个应用程序/游戏帧上调用此方法。这将通知XInputium现在可以执行输入循环的另一次迭代。任何输入事件现在都将被触发。
gamepad.Update();
在上面的示例中,XGamepad实例代表一个游戏手柄(或游戏控制器),当它被实例化时,它使用系统上第一个可用的设备(如果有的话)。XGamepad构造函数有多个重载,允许指定一个设备,甚至不指定任何设备。
gamepad.Update()方法是一切发生的地方。当调用这个方法时,gamepad实例的状态会用来自物理设备的新鲜信息更新,它的属性会更新,并且会触发相应的事件。在典型的应用程序或游戏中,会在每个图形帧调用一次这个方法。
使用动态事件 上面的“Hello world!”示例在按钮被按下时触发一个事件。可以使用事件参数参数(即e.Button)来确定哪个按钮被按下。这很好,但是当特定事情发生时触发的事件呢,比如当特定按钮保持一定时间?原生.NET事件是固定的——它们不允许指定事件如何被触发以及何时被触发;更糟糕的是,它们不允许按需创建新事件。为了解决这个问题,XInputium提供了动态事件——参与输入循环并在指定条件满足时触发的事件。
XInputium的动态事件是在XGamepad实例中注册的对象实例。这些对象派生自InputEvent类。有几个类派生自InputEvent,每个类代表可以注册的一种类型的动态事件。例如,DigitalButtonInputEvent在指定按钮被按下、释放或保持时触发,根据标准。还有其他动态事件适合其他任务,比如在用户按住按钮时重复触发(对于菜单和列表很有用),或者根据lambda函数执行操作等。
让看看如何注册一个动态事件,当用户按住按钮A 250毫秒时触发:
XGamepad gamepad = new XGamepad();
// 注册一个动态事件,当按钮A保持250ms时触发。
var buttonAHoldEvent = gamepad.RegisterButtonHoldEvent(XButtons.A, TimeSpan.FromMilliseconds(250), ButtonHeld);
// 在每个游戏/应用程序帧上调用此方法。
gamepad.Update();
// 可选地,当不再需要它时,稍后取消注册事件。
gamepad.UnregisterInputEvent(buttonAHoldEvent);
// 这个方法将处理事件,就像它处理常规.NET事件一样。
void ButtonHeld(object? sender, DigitalButtonInputEventArgs
在看到的示例中,gamepad.RegisterButtonHoldEvent()方法被调用来注册动态事件。这个方法创建了一个新的DigitalButtonInputEvent类实例,将其注册到输入循环中,将ButtonHeld()方法添加为事件处理程序,并返回创建的事件实例(这样可以稍后更改它,使用该实例取消注册事件或添加更多处理程序)。
XGamepad类有几种方法可以注册特定的动态事件,以及注册已经实例化的动态事件的方法。
动态事件允许制作非常酷的东西。例如,ActivationInputEvent类非常通用,允许指定一个回调函数,该函数被调用来确定何时触发事件,并且可以设置多个延迟,指示事件何时以及如何触发。这个事件允许执行诸如指示摇杆或触发器移动时忽略非常短的移动,或者根据用户按住跳跃按钮的时间使游戏角色跳得更高或更低,或者仅在一组按钮同时按下时触发等操作。
文档和进一步阅读 XInputium有许多特性。因为这篇文章只是一个介绍,已经看到了如何使用它的非常基础的内容,但可以在GitHub上的XInputium项目wiki部分找到更多信息和示例。