Managed DirectX 中的力反馈






4.54/5 (8投票s)
一个在 Managed DirectX 中使用力反馈的 C# 示例。

引言
Managed DirectX 是使用 .NET 语言编写 DirectX 应用程序的好方法,并且大多数 Managed DX 库都有很好的文档记录,健壮性强,并且在 Internet 上有很多示例。 自 2002 年首次发布以来,我就一直在断断续续地编写 Managed DX 代码,但直到最近才接触力反馈。
令我惊讶的是,我发现所有公开的 C# 力反馈代码示例在使用我的游戏手柄(Logitech 2 Rumble)时都会报错。 许多其他人在各种 Internet 论坛上发布了关于 Managed DirectX 和其他游戏手柄的这个问题,因此这似乎是 Managed DirectInput 库中一个长期存在的错误。 尽管有很多人报告了这个问题,但我无法找到适合我的解决方案 - 所以这里是我自己的解决方案。
附件中的项目提供了如何创建和触发几种不同力的示例,因此如果您是 C# 力反馈的新手,这里有您开始所需的一切。
背景
如果您想查看 Microsoft 的标准示例(对我不起作用),请访问此链接。
我最终找到的解决方案是独一无二的,但在一定程度上受到了Ayucar的一篇博客文章的启发。
Using the Code
附件中的项目包含所有代码,但如果您已经熟悉这些示例但仍然遇到“Value does not fall within expected range”错误,这里有一些(有些简化的)亮点。
基本设备初始化
Device Dev = null;
foreach ( DeviceInstance instance in Manager.GetDevices( DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly ) )
{
Dev = new Device( instance.InstanceGuid );
}
Dev.SetDataFormat( DeviceDataFormat.Joystick );
Dev.SetCooperativeLevel( Parent, CooperativeLevelFlags.Background |
CooperativeLevelFlags.Exclusive );
Dev.Properties.AxisModeAbsolute = true;
Dev.Properties.AutoCenter = false;
Dev.Acquire();
以上是 DirectInput 示例的典型示例。 AutoCenter = false
行对于力反馈尤其重要。 SetDataFormat
行中的 Parent
变量必须是 System.Windows.Forms.Control
。
查找轴
int[] axis = null;
// Enumerate any axes
foreach ( DeviceObjectInstance doi in Dev.Objects )
{
if ( ( doi.ObjectId & (int)DeviceObjectTypeFlags.Axis ) != 0 )
{
// We found an axis, set the range to a max of 10,000
Dev.Properties.SetRange( ParameterHow.ById,
doi.ObjectId, new InputRange( -5000, 5000 ) );
}
int[] temp;
// Get info about first two FF axii on the device
if ( ( doi.Flags & (int)ObjectInstanceFlags.Actuator ) != 0 )
{
if ( axis != null )
{
temp = new int[axis.Length + 1];
axis.CopyTo( temp, 0 );
axis = temp;
}
else
{
axis = new int[1];
}
// Store the offset of each axis.
axis[axis.Length - 1] = doi.Offset;
if ( axis.Length == 2 )
{
break;
}
}
}
在声明 int[]
temp 之前的所有内容都是您的标准 DirectInput 轴初始化 - 无论您是否使用力反馈,都必须执行这些操作。 轴数组计算是力反馈特有的,并且全部直接取自 Microsoft 示例(我没有在那里添加任何新内容)。
创建力
InitializeForce( Dev, EffectType.ConstantForce, axis,
10000, EffectFlags.ObjectOffsets | EffectFlags.Spherical, 250000 ) );
public static EffectObject InitializeForce( Device Dev, EffectType Type,
int[] Axis, int Magnitude, EffectFlags Flags, int Duration )
{
EffectObject eo = null;
Effect e;
foreach ( EffectInformation ei in Dev.GetEffects( EffectType.All ) )
{
if ( DInputHelper.GetTypeCode( ei.EffectType ) == (int)Type )
{
e = new Effect();
e.SetDirection( new int[Axis.Length] );
e.SetAxes( new int[1] );
e.EffectType = Type;
e.ConditionStruct = new Condition[Axis.Length];
e.Duration = Duration;
e.Gain = 10000;
e.Constant = new ConstantForce();
e.Constant.Magnitude = Magnitude;
e.SamplePeriod = 0;
e.TriggerButton = (int)Microsoft.DirectX.DirectInput.Button.NoTrigger;
e.TriggerRepeatInterval = (int)DI.Infinite;
e.Flags = Flags;
e.UsesEnvelope = false;
// Create the effect, using the passed in guid.
eo = new EffectObject( ei.EffectGuid, e, Dev );
}
}
return eo;
}
这是我的解决方案的用武之地。 通常出错的行是 e.SetAxes(new int[Axis.Length]);
它通常会抛出一个异常“Value does not fall within expected range”,这显然是 Managed DirectX 中的一个错误(至少影响某些游戏手柄)。 更改该行,使其始终初始化长度为 1 的轴数组,而不是长度为 2 的轴数组(如 Microsoft 示例所示),可以解决此问题,而且似乎对性能或功能没有任何其他副作用。
我应该注意到,由于同样的问题,我无法在 Managed DirectX 中成功加载 FFE 文件。 据推测,从 FFE 加载时的内部初始化代码也在尝试加载两个轴。 据我所知,这个问题存在于所有版本的 Managed DirectX 中,至少在 2008 年 3 月编写本文时是这样。
关注点
力反馈在大多数 PC 游戏中未得到充分利用,可能是因为该技术直到最近才在低端游戏手柄中可用。 将力反馈功能添加到您的游戏中是提供更身临其境的体验的好方法,也是在 PC 游戏市场中脱颖而出的一种小方式。
历史
- 版本 1:2008 年 3 月 16 日