日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用XInput库使用xbox360手柄

發布時間:2024/9/30 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用XInput库使用xbox360手柄 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

用XInput庫使用xbox360手柄

前言

XInput庫是微軟開發的庫,功能是讓xbox360類型的手柄能在Windows PC平臺使用。它被附帶在DXSDK_Jun10開發包中(我寫的框架基于這個版本),鏈接和實際使用都特別簡單。這篇文章應該可以讓你更快的使用上XInput。

環境配置

包含文件和DX11的配置一樣,頭文件都在同一個目錄下,如果之前配置了DX庫,就不需要額外做什么。只需要鏈接上附加依賴項 XInput.lib。
在代碼中也只需要包含頭文件XInput.h。

最后接口

class Input_imp;//輸入的單例類 class DLL_API GamePad { friend class Input_imp; public://按鍵狀態bool KeyUp(int pad);bool KeyDown(int pad);bool KeyState(int pad);//LT、RT的按下程度:[0,1]float ForceLT();float ForceRT();//LS、RS的位置偏移程度:[0,1]Vector2 GetLS();Vector2 GetRS();//LS、RS離原地的距離:[0,1]float ForceLS();float ForceRS();//設置振動,左右馬達的各自強度:[0,1]void SetVibration(Vector2 lr); private:UINT32 _id;//手柄編號 0-3Input_imp* _input; };

上面的值均規范化到0到1的范圍。
其中LT、RT需要返回按下的程度,在XInput庫中名字叫Trigger。LS、RS代表左右兩個搖桿,在Xinput中叫Thumb。
其它的按鈕均只有按下和非按下狀態,所以使用KeyUp、KeyDown、KeyState來返回它們的狀態。KeyUp代表上一幀按下,這一幀沒有按下。KeyDown代表上一幀沒按下,但此幀按下。KeyState返回當前是否按下。
單個狀態的按鈕枚舉值如下:

struct DLL_API PadCode { public:enum NAME{UP = 0x00000001,DOWN = 0x00000002,LEFT = 0x00000004,RIGHT = 0x00000008,START = 0x00000010,BACK = 0x00000020,LS = 0x00000040,RS = 0x00000080,LB = 0x0100,RB = 0x0200,A = 0x1000,B = 0x2000,X = 0x4000,Y = 0x8000}; };

通過名字,讀者就應該知道代表什么含義了。如果要檢測組合鍵應該使用第二種方式:

gamepad->KeyDown(UP | LEFT);//錯誤 gamepad->KeyDown(A) && gamepad->KeyDown(B);//正確

具體實現

由于暫時支持最多4個手柄,Input_imp類需要存儲4個GamePad類對象,4個當前按鍵狀態,4個上一幀按鍵狀態。用戶調用GetGamePad(N)時返回第N個手柄,如果手柄不存在,就返回NULL。

XINPUT_STATE _xinputState[MAX_CONTROLLERS];//當前狀態 XINPUT_STATE _xinputStatePre[MAX_CONTROLLERS];//上一幀狀態 GamePad _gamePad[MAX_CONTROLLERS];//手柄接口 bool _gamePadConnected[MAX_CONTROLLERS];//手柄是否連接

XINPUT_STATE結構體包含了手柄按鍵的所有狀態,如下

typedef struct _XINPUT_GAMEPAD {WORD wButtons; //單個狀態按鈕們的組合值BYTE bLeftTrigger;//LT [0,255]BYTE bRightTrigger;//RT [0,255]SHORT sThumbLX;//LS 的X軸位移 [-32768,32767]SHORT sThumbLY;//LS 的Y軸位移 [-32768,32767]SHORT sThumbRX;//RS 的X軸位移 [-32768,32767]SHORT sThumbRY;//RS 的Y軸位移 [-32768,32767] } XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;typedef struct _XINPUT_STATE {DWORD dwPacketNumber;XINPUT_GAMEPAD Gamepad; } XINPUT_STATE, *PXINPUT_STATE;

我們就在每幀調用下面的函數,獲取到手柄的按鈕狀態:

void Input_imp::_xinput_run() {DWORD dwResult;for (DWORD i = 0; i < MAX_CONTROLLERS; i++){_xinputStatePre[i] = _xinputState[i];//上一幀狀態ZeroMemory(&_xinputState[i], sizeof(XINPUT_STATE));// Simply get the state of the controller from XInput.dwResult = XInputGetState(i, &_xinputState[i]);if (dwResult == ERROR_SUCCESS){//獲取成功// Controller is connected _gamePadConnected[i] = true;}else{//獲取失敗,手柄不存在// Controller is not connected _gamePadConnected[i] = false;}}}

然后手柄狀態被存儲到了_xinputState中,接下來只需要GampPad類訪問即可,但其中需要做一些處理。第一是將數值規范化到[0,1],其次是過小的值需要歸0。所有成員函數的實現都列出來了,由于并不復雜,我就不多說了,許多直接copy自文檔,并做了一些改動(文檔的并不能直接使用)。

GamePad* Input_imp::GetGamePad(UINT32 id) {if (_gamePadConnected[id])return &_gamePad[id];elsereturn NULL; }bool GamePad::KeyUp(int pad) {return !(_input->_xinputState[_id].Gamepad.wButtons & pad) && (_input->_xinputStatePre[_id].Gamepad.wButtons & pad); }bool GamePad::KeyDown(int pad) {return (_input->_xinputState[_id].Gamepad.wButtons & pad) &&!(_input->_xinputStatePre[_id].Gamepad.wButtons & pad); }bool GamePad::KeyState(int pad) {return _input->_xinputState[_id].Gamepad.wButtons & pad; }float GamePad::ForceLT() {if (_input->_xinputState[_id].Gamepad.bLeftTrigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)return 0;return _input->_xinputState[_id].Gamepad.bLeftTrigger / 255.0f; }float GamePad::ForceRT() {BYTE ret = _input->_xinputState[_id].Gamepad.bRightTrigger;if (ret < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)return 0;return ret / 255.0f; }Vector2 GamePad::GetLS() {float LX = _input->_xinputState[_id].Gamepad.sThumbLX;float LY = -_input->_xinputState[_id].Gamepad.sThumbLY;if (abs(LX) < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)LX = 0;if (abs(LY) < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)LY = 0;if (LX == 0 && LY == 0)return Vector2();//determine how far the controller is pushedfloat magnitude = sqrt(LX*LX + LY*LY);//determine the direction the controller is pushedfloat normalizedLX = LX / magnitude;float normalizedLY = LY / magnitude;return Vector2(normalizedLX, normalizedLY); }Vector2 GamePad::GetRS() {float RX = _input->_xinputState[_id].Gamepad.sThumbRX;float RY = -_input->_xinputState[_id].Gamepad.sThumbRY;if (abs(RX) < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)RX = 0;if (abs(RY) < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)RY = 0; if (RX == 0 && RY == 0)return Vector2();//determine how far the controller is pushedfloat magnitude = sqrt(RX*RX + RY*RY);//determine the direction the controller is pushedfloat normalizedRX = RX / magnitude;float normalizedRY = RY / magnitude;return Vector2(normalizedRX, normalizedRY); }float GamePad::ForceLS() {//copy 自DirectX文檔float LX = _input->_xinputState[_id].Gamepad.sThumbLX;float LY = _input->_xinputState[_id].Gamepad.sThumbLY;//determine how far the controller is pushedfloat magnitude = sqrt(LX*LX + LY*LY);//determine the direction the controller is pushedfloat normalizedLX = LX / magnitude;float normalizedLY = LY / magnitude;float normalizedMagnitude = 0;//check if the controller is outside a circular dead zoneif (magnitude > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE){//clip the magnitude at its expected maximum valueif (magnitude > 32767) magnitude = 32767;//adjust magnitude relative to the end of the dead zonemagnitude -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;//optionally normalize the magnitude with respect to its expected range//giving a magnitude value of 0.0 to 1.0normalizedMagnitude = magnitude / (32767 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);}else //if the controller is in the deadzone zero out the magnitude{magnitude = 0.0f;normalizedMagnitude = 0.0f;}return normalizedMagnitude; }float GamePad::ForceRS() {//copy 自DirectX文檔float RX = _input->_xinputState[_id].Gamepad.sThumbLX;float RY = _input->_xinputState[_id].Gamepad.sThumbLY;//determine how far the controller is pushedfloat magnitude = sqrt(RX*RX + RY*RY);//determine the direction the controller is pushedfloat normalizedRX = RX / magnitude;float normalizedRY = RY / magnitude;float normalizedMagnitude = 0;//check if the controller is outside a circular dead zoneif (magnitude > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE){//clip the magnitude at its expected maximum valueif (magnitude > 32767) magnitude = 32767;//adjust magnitude relative to the end of the dead zonemagnitude -= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;//optionally normalize the magnitude with respect to its expected range//giving a magnitude value of 0.0 to 1.0normalizedMagnitude = magnitude / (32767 - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);}else //if the controller is in the deadzone zero out the magnitude{magnitude = 0.0f;normalizedMagnitude = 0.0f;}return normalizedMagnitude; }void GamePad::SetVibration(Vector2 lr) {XINPUT_VIBRATION vibration;ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION));vibration.wLeftMotorSpeed = lr.a * 65535; // use any value between 0-65535 herevibration.wRightMotorSpeed = lr.b * 65535; // use any value between 0-65535 hereXInputSetState(_id, &vibration);}

測試效果

下圖為通過手柄操作后的結果

實際的源碼請參考
https://github.com/Lveyou/DND
要運行此例子請跑其中的DNDTest項目

作者:吳泔游
QQ:1339484752
日期:2017-09-28

總結

以上是生活随笔為你收集整理的用XInput库使用xbox360手柄的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。