【Direct3D游戏开发】——DirectInput 让世界动起来

 其实我们是可以通过Windows消息和API取得键盘或者鼠标或者其他设备的输入信息,但这有个等待windows消息传送的延时,笔者试过直接在消息回调函数中相应键盘的上下左右消息去使场景中的模型进行旋转,感觉有明显的延时。这对于游戏玩家来说简直是噩梦,就好像我在玩lol,舍友都在用迅雷下AV一样的信息。而DirectX是直接与硬件进行交流,不需要去等待windows传送消息。DirectInput可以直接获得硬件的消息,立即响应。

  要用DirectInput获得一个硬件设备的信息和初始化Direct3D一样要经过几个步骤:

        1.创建DirectInput对象

        2.创建设备对象

        3.设定设备数据格式

        4.设定程序协调层级

        5.获得设备

        6.取得设备状态

  前面4步是初始化设备。

  1.创建DirectInput对象

        

//DirectInput8对象
    LPDIRECTINPUT8 pInputSystem;
//-1、创建DirectInput8对象
    hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, 
                            (VOID**)&pInputSystem, NULL );
    if( FAILED( hr ) )
    {
        MessageBox( NULL, L"DirectInput8Create()-FAILED!", NULL, MB_OK );
        return false;
    }
     首先声明一个DirectInput对象指针,然后调用DirectInput8Create()方法创建DirectInput对象,最后判断是否创建成功。具体参数含义可以查阅MSDN.
  2.创建设备对象 

     

//键盘设备
    LPDIRECTINPUTDEVICE8 pKeyboardDevice;
//-2、创建键盘DirectInput8Device
    hr = pInputSystem->CreateDevice( GUID_SysKeyboard, &pKeyboardDevice, NULL );
    if( FAILED(hr) )
    {
        MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );
        return false;
    }
   首先声明一个设备指针,然后调用DirectInput对象的成员函数CreateDevice()创建设备,这个创建的是键盘设备,具体由CreateDevice()的第一个参数决定,对于鼠标应为:GUID_SysMouse.


  3.设定设备数据格式


    //-3、设置键盘的数据格式
    hr = pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );
    if( FAILED( hr ) )
    {
        MessageBox( NULL, L"pKeyboardDevice->SetDataFormat()-FAILED!", NULL, MB_OK );
        return false;
    }

  由DirectInputDevice设备的SetDataFormat()成员函数完成,参数只有一个是一个关于数据格式的常量,对于鼠标有两种数据格式:c_dfDIMouse 、c_dfDIMouse2 用哪一个取决于先前声明的鼠标设备类型,但要保持前后一致。


  4.设定程序协同层级


//-4、设置设备合作等级
    hr = pKeyboardDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );
    if( FAILED(hr) )
    {
        MessageBox( NULL, L"pKeyboardDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );
        return false;
    }

   所谓的协同层级就是手你的程序如何和其他程序共同使用此设备。相关参数:
   DISL_BACKGROUND 程序当前非活跃,取得设备信息

   DISL_EXCLUSIVE 独占模式,其他程序无法使用程序所建立与使用的输入装置,设置前应先检查当前设备的协同等级

   DISL_FORCGROUND 程序只有在活跃时,才取得设备信息

   DISL_NONEXCLUSIVE非独占模型,与其他程序共享设备

   DISL_NOWINKEY 无法使用Windows键,防止使用者按下中断键导致程序结束

  5.获取设备

  

//-5、获取设备
        hr = pKeyboardDevice->Acquire();
        if( FAILED(hr) )
        {
            MessageBox( NULL, L"pMouseDevice->Acquire()-FAILED!", NULL, MB_OK );
            return false;
        }
   十分简单,调用设备的成员函数Acquire(), 检查是否获取成功。


  6.取得设备状态

if( FAILED(pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) )
        {
            if( FAILED( pKeyboardDevice->Acquire() ) )
                return false;
            if( FAILED( pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) )
            {
                MessageBox( NULL, L" pKeyboardDevice->GetDeviceState()-FAILED!", NULL, MB_OK );
                return false;
            }
        }

 也非常简单,调用设备的GetDeviceState()成员函数,一般在获取状态失败一次后再请求一次设备,然后获取设备状态。


  经过以上步骤就已经取得设备的当前状态,剩下的问题就是如何响应

  一、对于键盘消息

           

char keyboardState[256];
//方向键上按下
if( keyboardState[DIK_UP] & 0x80)
       //响应操作
//方向键右按下
if( keyboardState[DIK_RIGHT] & 0x80)
       //响应操作
//方向键下按下
if( keyboardState[DIK_DOWN] & 0x80)
       //响应操作
//方向键左按下
if( keyboardState[DIK_LEFT] & 0x80)
       //响应操作
  首先定义了一个256大小的数组作为输入缓冲区,代表键盘上256个键的状态,对于每一个键的状态是一个8bit的内存,高位代表键的状态。所以与(0x80)作And运算,如果不为0则代表此键被按下,反之未被按下。DIK_UP之类的是Direct的枚举类型。具体可查阅MSDN.


  二、对于鼠标

  对于鼠标在调用GetDeviceState()时需要在此函数的第二个参数传入一个类型为DIMOUSESTATE或DIMOUSESTATE2的结构体,以下是该结构体的定义


typedef struct DIMOUSESTATE {
    LONG lX;
    LONG lY;
    LONG lZ;
    BYTE rgbButtons[4];
} DIMOUSESTATE, *LPDIMOUSESTATE;

两个结构的的区别只在于最后一项rgbButtons[]的大小有所不同。当我们要响应鼠标消息时要利用到rgbButtons[]数组,rgbButtons[0]代表鼠标左键的状态,rgbButtons[1]代表鼠标右键的状态,同样采用 and (0x80)的方法判断键的状态。


  三、对于游戏控制器,手柄呀什么的判断哪个键是否被按下的方法还是一样只是取得的状态保存的结构不一样,具体这里不想说,可以查阅MSDN.

        一个封装后的DirectInput类,支持响应鼠标和键盘输入。

/********************************************************************
*						  游戏输入类								*
*		  file:		CLDirectInput.h								*
*	      copyright   (C) 2013 by CoderLing							*
*         email       : coderling@gmail.com 						*
*		  blog:	http://blog.csdn.net/coderling					*
********************************************************************/#ifndef CLDIRECTINPUT_H
#define CLDIRECTINPUT_H
#define DEBUG
#define DIM_LEFT 0
#define DIM_RIGHT 1
#define DIRECTINPUT_VERSION 0x0800
#define KEY_SIZE 256 //键盘数据大小#include <dinput.h>struct POINT3
{int x, y, z;POINT3( int _x, int _y, int _z){x = _x; y = _y; z = _z;}
};class CLDirectInput
{//---------------------------------------------//-1.处理键盘消息//----上下左右,字符消息//-2.处理鼠标消息//----鼠标左右键,中建//---------------------------------------------public:CLDirectInput();~CLDirectInput();
public://初始化directInputbool Initialize( HWND, HINSTANCE ); //更新设备当前状态bool UpdateDevices();//响应应键盘消息bool IsKeyDown( unsigned int );bool IsKeyUp( unsigned int );//响应鼠标消息bool IsMouseButtonDown( unsigned int );bool IsMouseButtonUp( unsigned int );long GetMouseWheelDir();POINT GetMousePos();POINT GetMousePosRel();
protected://由析构函数调用,释放资源void ShutDown();//DirectInput8对象LPDIRECTINPUT8 pInputSystem;//键盘设备LPDIRECTINPUTDEVICE8 pKeyboardDevice;char keysBuffer[KEY_SIZE];char keysBufferOld[KEY_SIZE];//鼠标设备LPDIRECTINPUTDEVICE8 pMouseDevice;DIMOUSESTATE mouseState;DIMOUSESTATE mouseStateOld;//鼠标位置信息,为移动量long xMousePos;long yMousePos;private:};#endif/********************************************************************
*						  游戏输入类								*
*		  file:		CLDirectInput.cpp									*
*	      copyright   (C) 2013 by CoderLing							*
*         email       : coderling@gmail.com 						*
*		  blog:	http://blog.csdn.net/coderling					*
********************************************************************/
#include "stdafx.h"
#include "LDirectInput.h"
#include <Windows.h>
#include <iostream>
#include <fstream>
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "DXGuid.lib")
//g构造函数
CLDirectInput::CLDirectInput():pInputSystem( NULL ), pKeyboardDevice( NULL ),pMouseDevice( NULL ), xMousePos( 0 ), yMousePos( 0 )
{memset( keysBuffer, 0, sizeof(char)*KEY_SIZE );memset( keysBufferOld, 0, sizeof(char)*KEY_SIZE );memset( &mouseState, 0, sizeof( mouseState ) );memset( &mouseStateOld, 0, sizeof( mouseStateOld ) );
}//析构函数
CLDirectInput::~CLDirectInput()
{ShutDown();
}//---------------------------------------------
//-name: Initialize()
//初始化DirectInput
//-1、创建DirectInput8对象
//-2、创建DirectInputDevice设备
//-3、设置设备数据格式,取决于何种设别
//-4、设置设备合作等级
//----------------------------------------------
bool CLDirectInput::Initialize(HWND hWnd, HINSTANCE hInst)
{HRESULT hr;HWND _hWnd = hWnd;//-1、创建DirectInput8对象hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&pInputSystem, NULL );if( FAILED( hr ) ){MessageBox( NULL, L"DirectInput8Create()-FAILED!", NULL, MB_OK );return false;}//---------键盘初始化---------------begin////-2、创建键盘DirectInput8Devicehr = pInputSystem->CreateDevice( GUID_SysKeyboard, &pKeyboardDevice, NULL );if( FAILED(hr) ){MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );return false;}//-3、设置键盘的数据格式hr = pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );if( FAILED( hr ) ){MessageBox( NULL, L"pKeyboardDevice->SetDataFormat()-FAILED!", NULL, MB_OK );return false;}//-4、设置设备合作等级hr = pKeyboardDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );if( FAILED(hr) ){MessageBox( NULL, L"pKeyboardDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );return false;}//清空缓冲区memset( keysBuffer, 0, sizeof(char)*KEY_SIZE );//------键盘初始化----------end////------鼠标初始化----------begin////-2、创建鼠标设备hr = pInputSystem->CreateDevice( GUID_SysMouse, &pMouseDevice, NULL );if( FAILED(hr) ){MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );return false;}//-3、设置鼠标数据格式hr = pMouseDevice->SetDataFormat( &c_dfDIMouse );if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->SetDataFormat()-FAILED!", NULL, MB_OK );return false;}//-4、设置设备合作等级hr = pMouseDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );return false;}//-----鼠标初始化--------end//return true;
}//----------------------------------------------
//-name:UpdateDevice()
//-更新设备状态
//-GetDeviceState()
//----------------------------------------------
bool CLDirectInput::UpdateDevices()
{HRESULT hr;//-更新鼠标信息if( pMouseDevice ){//-5、获取设备hr = pMouseDevice->Acquire();if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->Acquire()-FAILED!", NULL, MB_OK );return false;}memcpy( &mouseStateOld, &mouseState, sizeof(mouseState) );if( FAILED(pMouseDevice->GetDeviceState( sizeof(DIMOUSESTATE), (LPVOID)&mouseState )) ){if( FAILED(pMouseDevice->Acquire()) )return false;if( FAILED(pMouseDevice->GetDeviceState( sizeof(DIMOUSESTATE), (LPVOID)&mouseState )) ){MessageBox( NULL, L"pMouseDevice->GetDeviceState()-FAILED!", NULL, MB_OK );return false;}}xMousePos += mouseState.lX;yMousePos += mouseState.lY;}//-更新键盘信息if( pKeyboardDevice ){//-5、获取设备hr = pKeyboardDevice->Acquire();if( FAILED(hr) ){MessageBox( NULL, L"pKeyboardDevice->Acquire()-FAILED!", NULL, MB_OK );return false;}//保留信息用于比较memcpy( keysBufferOld, keysBuffer, sizeof(char)*KEY_SIZE );if( FAILED(pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) ){if( FAILED( pKeyboardDevice->Acquire() ) )return false;if( FAILED( pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) ){MessageBox( NULL, L" pKeyboardDevice->GetDeviceState()-FAILED!", NULL, MB_OK );return false;}}}
#ifndef DEBUGstd::ofstream out;out.open("text.txt");for(int i = 0;i < 256;i++){if(keysBuffer[i] != 0)out<<"dfadf"<<' ';}out<<std::endl <<std::endl;out.close();
#endifreturn true;
}//----------------------------------------------
//-name:IsKyeDown()
//-判断键盘是否有键被按下
//----------------------------------------------
bool CLDirectInput::IsKeyDown( unsigned int keyNum )
{return keysBuffer[keyNum] & 0x80;
}//----------------------------------------------
//-name:IsKeyUp()
//-判断键盘的键是否处于一般状态
//----------------------------------------------
bool CLDirectInput::IsKeyUp( unsigned int keyNum )
{//-如果此键没被按下,而且之前被按下return !(keysBuffer[keyNum] & 0x80) && (keysBuffer[keyNum] != keysBufferOld[keyNum]);
}//----------------------------------------
//-name:IsMouseButtonDown()
//-判断鼠标是否被按下
//----------------------------------------
bool CLDirectInput::IsMouseButtonDown( unsigned int buttonId )
{return mouseState.rgbButtons[buttonId] & 0x80;
}//---------------------------------------
//-name:IsMouseButtonUp()
//-判断按下的某键是否松开
//---------------------------------------
bool CLDirectInput::IsMouseButtonUp( unsigned int buttonId )
{return !(mouseState.rgbButtons[buttonId] & 0x80) &&(mouseState.rgbButtons[buttonId] != mouseStateOld.rgbButtons[buttonId]);
}//----------------------------------------
//-GetMouseRelative()
//-返回鼠标滚轮滚动方向,true代表向前
//----------------------------------------
long CLDirectInput::GetMouseWheelDir()
{return mouseState.lZ;
}//------------------------------------------
//-GetMousePos()
//-返回鼠标坐标
//-------------------------------------------
POINT CLDirectInput::GetMousePos()
{POINT pos;pos.x = xMousePos;pos.y = yMousePos;return pos;
}POINT CLDirectInput::GetMousePosRel()
{POINT rel;rel.x = mouseState.lX;rel.y = mouseState.lY;return rel;
}
//------------------------------------------
//-name:ShutDown()
//-释放相应资源
//------------------------------------------
void CLDirectInput::ShutDown()
{if (pInputSystem){pInputSystem->Release();pInputSystem = NULL;}if (pKeyboardDevice){pKeyboardDevice->Unacquire();pKeyboardDevice->Release();pKeyboardDevice = NULL;}if (pMouseDevice){pMouseDevice->Unacquire();pMouseDevice->Release();pMouseDevice = NULL;}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432194.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UE4多线程

UE4中最基础的模型就是FRunnable和FRunnableThread&#xff0c;FRunnable抽象出一个可以执行在线程上的对象&#xff0c;而FRunnableThread是平台无关的线程对象的抽象。后面的篇幅会详细讨论这些基础设施。 1. FRunnable UE4为我们抽象FRunnable的概念&#xff0c;让我们指定…

使用.net备份和还原数据库

使用.net备份和还原数据库 原文:使用.net备份和还原数据库CSDN网友的提问http://community.csdn.net/Expert/TopicView3.asp?id4929678C#实现SQLSERVER2000数据库备份还原的两种方法: 方法一&#xff08;不使用SQLDMO&#xff09;&#xff1a;//////备份方法///SqlConnection …

初识JavaScript,感觉整个人都不好了。。。

学习web前端的开发已经将近一个月了&#xff0c;开发中的三个大兄弟——“html”、“css”、“JavaScript”&#xff0c;小哥我已经深入接触了前两位&#xff0c;并与他俩建立的深厚的友谊。在编写过程中&#xff0c;不能说达到各位大神的程度&#xff0c;但是对各个标签、若干…

ue4-控制台执行方法

1. 引擎单例派生类可直接调用方法 以下类的派生类中可以通过在方法上标记 UFUNCTION(Exec) 直接调用方法 Pawns, Player Controllers, Player Input, Cheat Managers, Game Modes, Game Instances, overriden Game Engine classes, and Huds should all work by just adding t…

通过回调函数阻止进程创建(验证结束,方案完全可行)

&#xff08;此方案完全可行&#xff0c;只是我忘掉了一步&#xff09; 虽然Vista之后版本有进程创建回调函数的Ex版&#xff0c;而且Ex版可以拦截进程创建&#xff0c; 但是由于在Ex版回调函数内用第三个参数的最后一个元素来阻止进程创建的话&#xff0c;可能会出现弹框&…

UE4 多线程使用tip

在GameThread线程之外的其他线程中&#xff0c;不允许做一下事情 1. 不要 spawning / modifying / deleting UObjects / AActors 2. 不要使用定时器 TimerManager 3. 不要使用任何绘制接口&#xff0c;例如 DrawDebugLine 4. 如果想在主线程中异步处理&#xff08;也就是分帧…

linux shell if

linux_if 参数 shell 编程中使用到得if语句内判断参数 –b 当file存在并且是块文件时返回真 -c 当file存在并且是字符文件时返回真 -d 当pathname存在并且是一个目录时返回真 -e 当pathname指定的文件或目录存在时返回真 -f 当file存在并且是正规文件时返回真 -g 当由pathname指…

UE4异步操作总结

虚幻本身有提供一些对异步操作的封装&#xff0c;这里是对这段时间接触到的“非同步”的操作进行的总结。 当前使用的UE4版本为4.18.2。 在虚幻的游戏制作中&#xff0c;如果不是特殊情况一般不会有用到线程的时候。但是由于实际上虚幻内部是有着许多线程机制的。 例如通常的…

JavaScript模式读书笔记 第3章 字面量和构造函数

1&#xff0c;对象字面量 -1&#xff0c;Javascript中所创建的自定义对象在任务时候都是可变的。可以从一个空对象开始&#xff0c;根据需要增加函数。对象字面量模式可以使我们在创建对象的时候向其添加函数。<script>//定义空对象var dog {};//对空对象添加方法dog.na…

如何在UE4中创建线程

FRunnable和FRunnableThread方法对于大多数问题来说无疑是一个可行的解决方案。 但是&#xff0c;在创建许多任务时&#xff0c;您可能会达到CPU可以处理的并发上限&#xff0c;此时并发线程实际上会在争用CPU时间时相互阻碍。 然后可能值得查看FQueuedThreadPool以限制任务可用…

[Leveldb源码剖析疑问]-block_builder.cc之Add函数

Add函数是给一个Data block中添加对应的key和value,函数源码如下,其中有一处不理解: L30~L34是更新last_key_的,不理解这里干嘛不直接last_key_ key.ToString(); 写成 // Update state last_key_.resize(shared); last_key_.append(key.data() shared, non_shared); assert(S…

UE4多线程任务系统详解

首先&#xff0c;了解一下该系统重要的数据类型. 1. FQueuedThreadPool&#xff1a;虚基类&#xff0c;队列线程池, FQueuedThreadPoolBase继承自FQueuedThreadPool&#xff0c; FQueuedThreadPoolBase维护了一个TArray<IQueuedWork*> QueuedWork(需要被执行的工作)…

UE4异步编程专题 - 线程池FQueuedThreadPool

1. FQueuedThreadPool & IQueuedWork FQueuedThreadPool是UE4中抽象出的线程池。线程池由若干个Worker线程&#xff0c;和一个同步队列构成。UE4把同步队列执行的任务抽象为IQueuedWork. 线程池的同步队列&#xff0c;就是一个IQueuedWork的队列了。借用wiki上线程池的图,…

UE4异步编程专题 - 多线程

专题的第二篇&#xff0c;我们聊聊UE4中的多线程的基础设施。UE4中最基础的模型就是FRunnable和FRunnableThread&#xff0c;FRunnable抽象出一个可以执行在线程上的对象&#xff0c;而FRunnableThread是平台无关的线程对象的抽象。后面的篇幅会详细讨论这些基础设施。 1. FRu…

坑爹的UICollectionView

最近用UICoolectionView的时候遇到一个很DT的问题&#xff0c;我往VC里加12个视图&#xff0c;结果显示成这样&#xff08;右边是期待的样子&#xff09;&#xff1a; 研究了一下午&#xff0c;终于发现了问题&#xff1a; interface FpLabelCell : UICollectionViewCellproper…

UE4异步编程专题 - TFunction

0. 关于这个专题 游戏要给用户良好的体验&#xff0c;都会尽可能的保证60帧或者更高的fps。一帧留给引擎的时间也不过16ms的时长&#xff0c;再除去渲染时间&#xff0c;留给引擎时间连10ms都不到&#xff0c;能做的事情是极其有限的。同步模式执行耗时的任务&#xff0c;时长…

Python用subprocess的Popen来调用系统命令

当我们须要调用系统的命令的时候&#xff0c;最先考虑的os模块。用os.system()和os.popen()来进行操作。可是这两个命令过于简单&#xff0c;不能完毕一些复杂的操作&#xff0c;如给执行的命令提供输入或者读取命令的输出&#xff0c;推断该命令的执行状态&#xff0c;管理多个…

7700装win7

1.可能不能安装版本太新的win7系统,会蓝屏 2.第一次重启后,系统会提示硬件太新,系统不支持,不用理会.可以用shiftF10,进入windows/system32/oobe目录,执行msoobe手动安装. 3.第一次进入系统后,尽早关闭系统更新,除了在控制面板中关闭,还要在services.msc中关闭windows update服…

UE4高级功能--初探超大无缝地图的实现LevelStream

LevelStream 实现超大无缝地图--官方文档学习 The Level Streaming feature makes it possible to load and unload map files into memory as well as toggle their visibility all during play. This makes it possible to have worlds broken up into smaller chunks so th…

Noip 2014酱油记+简要题解

好吧&#xff0c;day2T1把d默认为1也是醉了&#xff0c;现在只能期待数据弱然后怒卡一等线吧QAQDay0 第一次下午出发啊真是不错&#xff0c;才2小时左右就到了233&#xff0c;在车上把sao和fate补掉就到了 然后到宾馆之后&#xff0c;没wifi的生活就是惨啊QAQ 把空境补完就睡了…