正确的方法来抽象XBox控制器


12

我有一个XBox360控制器,我想将其用作应用程序的输入。

我无法解决的是通过接口公开此内容的最佳实践方法。

在幕后,处理控制器的类依赖于轮询按钮状态。

我最初尝试了一些链接:

Event ButtonPressed() as ButtonEnum

这里ButtonEnumButtonRedButtonStart等...

这是有一点限制的,因为它仅支持按钮按下,不支持按住/模式(按两次,等等)。

下一个想法是简单地向应用程序公开按钮状态,例如

Property RedPressed as Boolean
Property StartPressed as Boolean
Property Thumb1XAxis as Double

这是非常灵活的方法,但实际上它会迫使应用程序投入过多工作,并且需要应用程序进行轮询-如果可能的话,我更喜欢事件驱动。

我考虑添加多个事件,例如:

Event ButtonPressed(Button as ButtonEnum)
Event ButtonPressedTwice(Button as ButtonEnum)
Event ButtonHeldStart(Button as ButtonEnum)
Event ButtonHeldEnd(Button as ButtonEnum)

但这似乎有些笨拙,并且在“绑定按钮”屏幕上确实很痛苦。

有人可以给我指出处理控制器输入的“正确”方法。

注意:我在实现接口的类中使用SlimDX。这使我可以非常轻松地读取状态。任何可以解决我的问题的替代方案也将受到赞赏

Answers:


21

没有一种完美的映射可以为您提供特定于平台的抽象,因为显然对360控制器有意义的大多数标识符对于PlayStation控制器都是错误的(A代替X,B代替Circle)。当然,Wii控制器是另一回事。

我发现解决此问题的最有效方法是使用三层实施。下层完全是平台/控制器专用的,并且知道有多少个数字按钮和模拟轴可用。正是这一层知道如何轮询硬件状态,并且正是这一层可以很好地记住以前的状态,从而知道何时按下了按钮,是否按下了一个以上的滴答声或是否未按下按钮。除此之外,它是愚蠢的-代表单一类型控制器的纯状态类。真正的价值是从中间层抽象出查询控制器状态的精髓。

中间层是实际控件从真实按钮到游戏概念的映射(例如A-> Jump)。我们称它们为脉冲而不是按钮,因为它们不再绑定到特定的控制器类型。您可以在此层上重新映射控件(在开发过程中或在运行时,应用户要求)。每个平台都有其自己的控件到虚拟脉冲的映射。您不能也不应该试图摆脱这一点。每个控制器都是唯一的,并且需要自己的映射。按钮可以映射到一个以上的脉冲(取决于游戏模式),并且多个按钮可以映射到相同的脉冲(例如A和X都加速,B和Y都减速)。映射定义了所有这些,

上层是游戏层。它需要冲动,而不在乎它们是如何产生的。也许它们来自控制器,或者来自控制器的记录,或者它们来自AI。在此级别上,您不在乎。您所关心的是,有一个新的“跳跃”脉冲,或者“加速”脉冲已经持续,或者“潜水”脉冲的价值为0.35。

在这种系统中,您为每个控制器编写一次底层。上层是平台无关的。中间层的代码只需要编写一次,但是每个平台/控制器的数据(重映射)都需要重做。


这似乎是一种非常干净优雅的方法。谢谢!
基本

1
非常好。比我好得多:P
Jordaan Mylonas

3
非常好的抽象。但实施时要小心:不要为每个用户操作创建和销毁新的脉冲对象。使用池化。垃圾收集器将感谢您。
grega g

绝对。大小最大为同时发生脉冲数的静态阵列几乎总是最佳选择。因为几乎总是您一次都希望每个脉冲只有一个实例处于活动状态。大多数情况下,该数组中只有几个项目,因此可以快速迭代。
MrCranky 2011年

@grega谢谢你们两个-我没想到。
基本

1

老实说,我想说最佳界面在很大程度上取决于游戏中的使用情况。但是,对于一般使用情况,我建议使用两层体系结构,该体系结构将基于事件的方法和基于轮询的方法分开。

较低的层可以被认为是“基于轮询的”层,并且公开了按钮的当前状态。一个这样的界面可以简单地有2个功能,GetAnalogState(InputIdentifier)GetDigitalState(InputIdentifier)在那里InputIdentifier是代表哪个按钮,触发一个枚举值还是坚持你对检查。(如果为按钮运行GetAnalogState将返回1.0或0.0,而为模拟摇杆运行GetDigitalState将返回true(如果超过预设阈值),否则返回false)。

然后,第二层将使用较低层在状态更改时生成事件,并允许元素注册回调(C#事件是光荣的)。这些回调将包括按下,释放,点击,长按等事件。对于模拟摇杆,您可以包括手势,例如格斗游戏的QCF。公开的事件数取决于您要调度的事件的详细程度。ButtonStateChanged(InputIdentifier)如果您想以单独的逻辑处理其他所有事情,则只需触发一个简单的操作即可。

因此,如果您需要检查输入按钮或控制杆的当前状态,请检查下层。如果您只想在输入事件时触发一个函数,请注册第二层的回调。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.