【Direct3D游戏开发】——DirectInput 让世界动起来
?其實(shí)我們是可以通過Windows消息和API取得鍵盤或者鼠標(biāo)或者其他設(shè)備的輸入信息,但這有個(gè)等待windows消息傳送的延時(shí),筆者試過直接在消息回調(diào)函數(shù)中相應(yīng)鍵盤的上下左右消息去使場景中的模型進(jìn)行旋轉(zhuǎn),感覺有明顯的延時(shí)。這對于游戲玩家來說簡直是噩夢,就好像我在玩lol,舍友都在用迅雷下AV一樣的信息。而DirectX是直接與硬件進(jìn)行交流,不需要去等待windows傳送消息。DirectInput可以直接獲得硬件的消息,立即響應(yīng)。
??要用DirectInput獲得一個(gè)硬件設(shè)備的信息和初始化Direct3D一樣要經(jīng)過幾個(gè)步驟:
????????1.創(chuàng)建DirectInput對象
????????2.創(chuàng)建設(shè)備對象
????????3.設(shè)定設(shè)備數(shù)據(jù)格式
????????4.設(shè)定程序協(xié)調(diào)層級
????????5.獲得設(shè)備
????????6.取得設(shè)備狀態(tài)
??前面4步是初始化設(shè)備。
??1.創(chuàng)建DirectInput對象
????????
//DirectInput8對象
?? ?LPDIRECTINPUT8 pInputSystem;
//-1、創(chuàng)建DirectInput8對象
?? ?hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8,?
?? ??? ??? ??? ??? ??? ??? ?(VOID**)&pInputSystem, NULL );
?? ?if( FAILED( hr ) )
?? ?{
?? ??? ?MessageBox( NULL, L"DirectInput8Create()-FAILED!", NULL, MB_OK );
?? ??? ?return false;
?? ?}
?????首先聲明一個(gè)DirectInput對象指針,然后調(diào)用DirectInput8Create()方法創(chuàng)建DirectInput對象,最后判斷是否創(chuàng)建成功。具體參數(shù)含義可以查閱MSDN.
??2.創(chuàng)建設(shè)備對象?
?????
//鍵盤設(shè)備
?? ?LPDIRECTINPUTDEVICE8 pKeyboardDevice;
//-2、創(chuàng)建鍵盤DirectInput8Device
?? ?hr = pInputSystem->CreateDevice( GUID_SysKeyboard, &pKeyboardDevice, NULL );
?? ?if( FAILED(hr) )
?? ?{
?? ??? ?MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );
?? ??? ?return false;
?? ?}
???首先聲明一個(gè)設(shè)備指針,然后調(diào)用DirectInput對象的成員函數(shù)CreateDevice()創(chuàng)建設(shè)備,這個(gè)創(chuàng)建的是鍵盤設(shè)備,具體由CreateDevice()的第一個(gè)參數(shù)決定,對于鼠標(biāo)應(yīng)為:GUID_SysMouse.
??3.設(shè)定設(shè)備數(shù)據(jù)格式
?? ?//-3、設(shè)置鍵盤的數(shù)據(jù)格式
?? ?hr = pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );
?? ?if( FAILED( hr ) )
?? ?{
?? ??? ?MessageBox( NULL, L"pKeyboardDevice->SetDataFormat()-FAILED!", NULL, MB_OK );
?? ??? ?return false;
?? ?}
??由DirectInputDevice設(shè)備的SetDataFormat()成員函數(shù)完成,參數(shù)只有一個(gè)是一個(gè)關(guān)于數(shù)據(jù)格式的常量,對于鼠標(biāo)有兩種數(shù)據(jù)格式:c_dfDIMouse 、c_dfDIMouse2 用哪一個(gè)取決于先前聲明的鼠標(biāo)設(shè)備類型,但要保持前后一致。
??4.設(shè)定程序協(xié)同層級
//-4、設(shè)置設(shè)備合作等級
?? ?hr = pKeyboardDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );
?? ?if( FAILED(hr) )
?? ?{
?? ??? ?MessageBox( NULL, L"pKeyboardDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );
?? ??? ?return false;
?? ?}
???所謂的協(xié)同層級就是手你的程序如何和其他程序共同使用此設(shè)備。相關(guān)參數(shù):
???DISL_BACKGROUND 程序當(dāng)前非活躍,取得設(shè)備信息
???DISL_EXCLUSIVE 獨(dú)占模式,其他程序無法使用程序所建立與使用的輸入裝置,設(shè)置前應(yīng)先檢查當(dāng)前設(shè)備的協(xié)同等級
???DISL_FORCGROUND 程序只有在活躍時(shí),才取得設(shè)備信息
???DISL_NONEXCLUSIVE非獨(dú)占模型,與其他程序共享設(shè)備
???DISL_NOWINKEY 無法使用Windows鍵,防止使用者按下中斷鍵導(dǎo)致程序結(jié)束
??5.獲取設(shè)備
??
//-5、獲取設(shè)備
?? ??? ?hr = pKeyboardDevice->Acquire();
?? ??? ?if( FAILED(hr) )
?? ??? ?{
?? ??? ??? ?MessageBox( NULL, L"pMouseDevice->Acquire()-FAILED!", NULL, MB_OK );
?? ??? ??? ?return false;
?? ??? ?}
???十分簡單,調(diào)用設(shè)備的成員函數(shù)Acquire(), 檢查是否獲取成功。
??6.取得設(shè)備狀態(tài)
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;
?? ??? ??? ?}
?? ??? ?}
?也非常簡單,調(diào)用設(shè)備的GetDeviceState()成員函數(shù),一般在獲取狀態(tài)失敗一次后再請求一次設(shè)備,然后獲取設(shè)備狀態(tài)。
??經(jīng)過以上步驟就已經(jīng)取得設(shè)備的當(dāng)前狀態(tài),剩下的問題就是如何響應(yīng)
??一、對于鍵盤消息
???????????
char keyboardState[256];
//方向鍵上按下
if( keyboardState[DIK_UP] & 0x80)
? ? ? ?//響應(yīng)操作
//方向鍵右按下
if( keyboardState[DIK_RIGHT] & 0x80)
? ? ? ?//響應(yīng)操作
//方向鍵下按下
if( keyboardState[DIK_DOWN] & 0x80)
? ? ? ?//響應(yīng)操作
//方向鍵左按下
if( keyboardState[DIK_LEFT] & 0x80)
? ? ? ?//響應(yīng)操作
??首先定義了一個(gè)256大小的數(shù)組作為輸入緩沖區(qū),代表鍵盤上256個(gè)鍵的狀態(tài),對于每一個(gè)鍵的狀態(tài)是一個(gè)8bit的內(nèi)存,高位代表鍵的狀態(tài)。所以與(0x80)作And運(yùn)算,如果不為0則代表此鍵被按下,反之未被按下。DIK_UP之類的是Direct的枚舉類型。具體可查閱MSDN.
??二、對于鼠標(biāo)
??對于鼠標(biāo)在調(diào)用GetDeviceState()時(shí)需要在此函數(shù)的第二個(gè)參數(shù)傳入一個(gè)類型為DIMOUSESTATE或DIMOUSESTATE2的結(jié)構(gòu)體,以下是該結(jié)構(gòu)體的定義
typedef struct DIMOUSESTATE {
? ? LONG lX;
? ? LONG lY;
? ? LONG lZ;
? ? BYTE rgbButtons[4];
} DIMOUSESTATE, *LPDIMOUSESTATE;
兩個(gè)結(jié)構(gòu)的的區(qū)別只在于最后一項(xiàng)rgbButtons[]的大小有所不同。當(dāng)我們要響應(yīng)鼠標(biāo)消息時(shí)要利用到rgbButtons[]數(shù)組,rgbButtons[0]代表鼠標(biāo)左鍵的狀態(tài),rgbButtons[1]代表鼠標(biāo)右鍵的狀態(tài),同樣采用 and (0x80)的方法判斷鍵的狀態(tài)。
??三、對于游戲控制器,手柄呀什么的判斷哪個(gè)鍵是否被按下的方法還是一樣只是取得的狀態(tài)保存的結(jié)構(gòu)不一樣,具體這里不想說,可以查閱MSDN.
????????一個(gè)封裝后的DirectInput類,支持響應(yīng)鼠標(biāo)和鍵盤輸入。
/******************************************************************** * 游戲輸入類 * * 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 //鍵盤數(shù)據(jù)大小#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.處理鼠標(biāo)消息//----鼠標(biāo)左右鍵,中建//---------------------------------------------public:CLDirectInput();~CLDirectInput(); public://初始化directInputbool Initialize( HWND, HINSTANCE ); //更新設(shè)備當(dāng)前狀態(tài)bool UpdateDevices();//響應(yīng)應(yīng)鍵盤消息bool IsKeyDown( unsigned int );bool IsKeyUp( unsigned int );//響應(yīng)鼠標(biāo)消息bool IsMouseButtonDown( unsigned int );bool IsMouseButtonUp( unsigned int );long GetMouseWheelDir();POINT GetMousePos();POINT GetMousePosRel(); protected://由析構(gòu)函數(shù)調(diào)用,釋放資源void ShutDown();//DirectInput8對象LPDIRECTINPUT8 pInputSystem;//鍵盤設(shè)備LPDIRECTINPUTDEVICE8 pKeyboardDevice;char keysBuffer[KEY_SIZE];char keysBufferOld[KEY_SIZE];//鼠標(biāo)設(shè)備LPDIRECTINPUTDEVICE8 pMouseDevice;DIMOUSESTATE mouseState;DIMOUSESTATE mouseStateOld;//鼠標(biāo)位置信息,為移動量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構(gòu)造函數(shù) 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 ) ); }//析構(gòu)函數(shù) CLDirectInput::~CLDirectInput() {ShutDown(); }//--------------------------------------------- //-name: Initialize() //初始化DirectInput //-1、創(chuàng)建DirectInput8對象 //-2、創(chuàng)建DirectInputDevice設(shè)備 //-3、設(shè)置設(shè)備數(shù)據(jù)格式,取決于何種設(shè)別 //-4、設(shè)置設(shè)備合作等級 //---------------------------------------------- bool CLDirectInput::Initialize(HWND hWnd, HINSTANCE hInst) {HRESULT hr;HWND _hWnd = hWnd;//-1、創(chuàng)建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、創(chuàng)建鍵盤DirectInput8Devicehr = pInputSystem->CreateDevice( GUID_SysKeyboard, &pKeyboardDevice, NULL );if( FAILED(hr) ){MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );return false;}//-3、設(shè)置鍵盤的數(shù)據(jù)格式hr = pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );if( FAILED( hr ) ){MessageBox( NULL, L"pKeyboardDevice->SetDataFormat()-FAILED!", NULL, MB_OK );return false;}//-4、設(shè)置設(shè)備合作等級hr = pKeyboardDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );if( FAILED(hr) ){MessageBox( NULL, L"pKeyboardDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );return false;}//清空緩沖區(qū)memset( keysBuffer, 0, sizeof(char)*KEY_SIZE );//------鍵盤初始化----------end////------鼠標(biāo)初始化----------begin////-2、創(chuàng)建鼠標(biāo)設(shè)備hr = pInputSystem->CreateDevice( GUID_SysMouse, &pMouseDevice, NULL );if( FAILED(hr) ){MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );return false;}//-3、設(shè)置鼠標(biāo)數(shù)據(jù)格式hr = pMouseDevice->SetDataFormat( &c_dfDIMouse );if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->SetDataFormat()-FAILED!", NULL, MB_OK );return false;}//-4、設(shè)置設(shè)備合作等級hr = pMouseDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );return false;}//-----鼠標(biāo)初始化--------end//return true; }//---------------------------------------------- //-name:UpdateDevice() //-更新設(shè)備狀態(tài) //-GetDeviceState() //---------------------------------------------- bool CLDirectInput::UpdateDevices() {HRESULT hr;//-更新鼠標(biāo)信息if( pMouseDevice ){//-5、獲取設(shè)備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、獲取設(shè)備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() //-判斷鍵盤的鍵是否處于一般狀態(tài) //---------------------------------------------- bool CLDirectInput::IsKeyUp( unsigned int keyNum ) {//-如果此鍵沒被按下,而且之前被按下return !(keysBuffer[keyNum] & 0x80) && (keysBuffer[keyNum] != keysBufferOld[keyNum]); }//---------------------------------------- //-name:IsMouseButtonDown() //-判斷鼠標(biāo)是否被按下 //---------------------------------------- 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() //-返回鼠標(biāo)滾輪滾動方向,true代表向前 //---------------------------------------- long CLDirectInput::GetMouseWheelDir() {return mouseState.lZ; }//------------------------------------------ //-GetMousePos() //-返回鼠標(biāo)坐標(biāo) //------------------------------------------- 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() //-釋放相應(yīng)資源 //------------------------------------------ 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;} }?
總結(jié)
以上是生活随笔為你收集整理的【Direct3D游戏开发】——DirectInput 让世界动起来的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea maven创建java项目_新
- 下一篇: 8999元 vivo X Fold手机6