游戏开发论坛

 找回密码
 立即注册
搜索
查看: 6928|回复: 1

Delphi游戏编程导学——DirectInput(补完篇)

[复制链接]

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
发表于 2007-4-8 03:14:00 | 显示全部楼层 |阅读模式
这次主要介绍游戏控制器的使用,还有力反馈的实现。

上次有关DirectInput的教学,我并没有写完。这次我抽空把DirectInput的内容补充完整。

首先是DIpnut对象销毁的问题。在VCL环境里,你不用自己销毁COM对象。因为DX的对象都是COM对象,所以你就不用自己销毁DX对象(DInput包含在DX里,不要告诉我你不知道!)。上次我已经说过这个问题了,不过我说在程序结束时要调用Unacquire,经过测试,这一步是完全没有必要的。因此,DInput对象的释放,我们根本就不用写任何代码。 [em3]
另外,在设置键盘设备的合作级别时,可以设置为独占级别,这时无需指定屏蔽Windows键就能屏蔽所有Windows系统键(除了Alt+Tab和Ctrl+Alt+Del)

下面是这次的重点:游戏控制器!
我这里说的游戏控制器就是Windows控制面板里的游戏控制器。包括各种游戏手柄、方向盘、摇杆……,玩过游戏机的应该知道是什么吧。如果你连游戏机都没玩过,还是不要搞游戏编程了。

接下来,我以手柄为例,介绍如何得到它的数据,还有如何控制最让人兴奋的震动功能。
为了使用手柄,我们需要几个新的变量和函数:
    joy_state        : DIJOYSTATE2;
    DInputJoy        : IDirectInputDevice8;
    DInputEffect     : IDirectInputEffect;   //用于实现震动
    NumFFBAxis       : DWORD;   //Numbers of Force Feed Back Axis
                                //简单说,就是你的手柄有几个震动电机
    nXForce,
    nYForce          : Integer; //震动的强弱
    procedure SetFFB;           //执行震动

注:这篇教学是基于上次的程序,我只修改了变量名称(去掉了 F 字头)。

然后我们要利用已有的DInput接口创建手柄设备。
创建手柄时,我们使用枚举函数,调用一个回调函数来创建设备:
//我们创建了一个支持力反馈的设备
DInput.EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoyCallback,
                   nil, DIEDFL_ATTACHEDONLY or DIEDFL_FORCEFEEDBACK);
回调函数的定义如下:
(注意:回调函数不能是类成员函数)
function EnumJoyCallback(var lpddi: DIDeviceInstance; pvRef: Pointer): BOOL;
begin
  Form1.DInput.CreateDevice(lpddi.guidInstance, Form1.DInputJoy, nil);
//只创建第一个设备,然后结束枚举
  Result := DIENUM_STOP;
end;

接着设置合作级别和数据格式,这些和键盘/鼠标类似
DInputJoy.SetCooperativeLevel(Self.Handle, DISCL_EXCLUSIVE or DISCL_FOREGROUND);
DInputJoy.SetDataFormat(c_dfDIJoystick2);

现在我们要看看手柄有几个震动电机了,还是一个枚举函数,又使用了一个回调函数
  DInputJoy.EnumObjects(EnumAxesCallback, nil, DIDFT_AXIS);
回调函数的定义如下:
function EnumAxesCallback(var lpddoi: DIDeviceObjectInstance; pvRef : Pointer): BOOL; stdcall;
var
  dirange : DIPROPRANGE;
begin
  if (lpddoi.dwFlags and DIDOI_FFACTUATOR) <> 0 then
  begin
    Inc(Form1.NumFFBAxis);
  end;
  Result := DIENUM_CONTINUE;
end;
如果手柄有多个震动电机,我们只使用两个
  if NumFFBAxis > 2 then
    NumFFBAxis := 2;

我们还要设置一下手柄上摇杆的取值范围,还是刚才那个枚举函数,不过使用了另一个回调函数(我保证这是最后一个枚举函数!)
DInputJoy.EnumObjects(EnumObjCallback, nil, DIDFT_ALL);
最后一个回调函数的定义如下:
function EnumObjCallback(var lpddoi: DIDeviceObjectInstance; pvRef : Pointer): BOOL; stdcall;
var
  dirange : DIPROPRANGE;
begin
  if (lpddoi.dwType and DIDFT_AXIS) > 0 then
  begin
    dirange.diph.dwSize       := SizeOf(DIPROPRANGE);
    dirange.diph.dwHeaderSize := SizeOf(DIPROPHEADER);
    dirange.diph.dwHow        := DIPH_BYID;
    dirange.diph.dwObj        := lpddoi.dwType;
    dirange.lMin              := -1000;
    dirange.lMax              := +1000;

    Form1.DInputJoy.SetProperty(DIPROP_RANGE, dirange.diph);
  end;

  Result := DIENUM_CONTINUE;
end;

接着(对,还没完)要通过刚才创建的手柄设备来生成一个效果对象,首先初始化几个变量
  Axes[0]       := DIJOFS_X;
  Axes[1]       := DIJOFS_Y;
  Direction[0]  := 0;
  Direction[1]  := 0;
  cf.lMagnitude := 0;

  ZeroMemory(@eff, SizeOf(eff) );
  eff.dwSize                  := SizeOf(DIEFFECT);
  eff.dwFlags                 := DIEFF_CARTESIAN or DIEFF_OBJECTOFFSETS;
  eff.dwDuration              := INFINITE;
  eff.dwSamplePeriod          := 0;
  eff.dwGain                  := DI_FFNOMINALMAX;
  eff.dwTriggerButton         := DIEB_NOTRIGGER;
  eff.dwTriggerRepeatInterval := 0;
  eff.cAxes                   := NumFFBAxis;
  eff.rgdwAxes                := @Axes;
  eff.rglDirection            := @Direction;
  eff.lpEnvelope              := 0;
  eff.cbTypeSpecificParams    := SizeOf(DICONSTANTFORCE);
  eff.lpvTypeSpecificParams   := @cf;
  eff.dwStartDelay            := 0;
然后生成效果对象
DInputJoy.CreateEffect(GUID_ConstantForce,  @eff, DInputEffect, nil);
初始化的最后一步终于到了!获得手柄设备:
DInputJoy.Acquire;

终于要动真格的了,我们要获取手柄的数据同时实现震动功能。
在获取键盘和鼠标数据的地方加入以下代码
//有些游戏控制器需要这个函数
DInputJoy.Poll;
//获取手柄数据
DInputJoy.GetDeviceState(SizeOf(DIJOYSTATE2), @joy_state);
//在得到摇杆数据的同时设置震动等级
    nXForce := ABS(joy_state.lX) * 30 div 1000;
    nYForce := ABS(joy_state.lY) * 30 div 1000;
//得到手柄按钮数据
    for i := 0 to 127 do
    begin
      if joy_state.rgbButtons <> 0 then
      begin
        Self.Canvas.TextOut(0, 140, 'Joy-Buttons: ' + IntToStr(i));
      end;
    end;
//这是干什么用的呢?
    SetFFB;

最后一个函数就是让手柄震动的关键。要看他的定义吗?去下载我这篇教学的完整源代码吧。  [em1]


相关内容的更多信息请参考微软的DX9SDK


以下是这篇教学的演示以及源代码下载地址:
http://www.box.net/shared/cxim446zhu

27

主题

418

帖子

455

积分

中级会员

Rank: 3Rank: 3

积分
455
QQ
 楼主| 发表于 2007-9-21 11:14:00 | 显示全部楼层

Re: Delphi游戏编程导学——DirectInput(补完篇)

自己顶一下。 [em10]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-17 00:48

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表