29:ゲームパッドによるアナログ入力
ゲームパッドの中には十字キーによる入力をアナログ形式で伝達する天の邪鬼な機器も存在します。今回は、そんなアナログ入力に対応するための方法をご紹介。列挙用関数では、DIPROPRANGE構造体に、システムから送られてきたパッドのアナログ箇所に対する設定を代入し、対象のIDirectInputDevice8に対し、SetProperty関数でこの構造体のDIPROPHEADERのポインタを用いれば、アナログ入力の範囲が反映されます。今回のサンプルプログラムでは、-10~0~10の21段階になるようにしています。
/* 省略 */
class CInput : public CGameObject
{
private:
/* 省略 */
static BOOL CALLBACK EnumJoypad(const DIDEVICEINSTANCE* pInstance, LPVOID pContext);
static BOOL CALLBACK EnumObject(LPCDIDEVICEOBJECTINSTANCE pInstance, LPVOID pvRef);
public:
/* 省略 */
};
/* 省略 */
void CInput::Init()
{
if(pInput == NULL){
/* 省略 */
// ジョイパッドの作成
enumdata ed;
ed.pInput = pInput;
ed.ppPadDevice = &pPadDevice;
pInput->EnumDevices(
DI8DEVCLASS_GAMECTRL, EnumJoypad,
&ed, DIEDFL_ATTACHEDONLY);
if(pPadDevice){
// アナログキーのデータを設定
// 2番目の引数にpPadDeviceを指定しておくと、
// EnumObject関数のpvRefに、このpPadDeviceが格納されるようになるため、
// pPadDeviceをスタティックやグローバル変数にしなくて済む。
pPadDevice->EnumObjects(EnumObject, pPadDevice, DIDFT_AXIS);
pPadDevice->SetCooperativeLevel(GetHWnd(),
DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
hr = pPadDevice->SetDataFormat(&c_dfDIJoystick2);
if(FAILED(hr)) RELEASE(pPadDevice);
}
}
}
BOOL CALLBACK CInput::EnumObject(LPCDIDEVICEOBJECTINSTANCE pInstance, LPVOID pvRef)
{
DIPROPRANGE range;
range.diph.dwSize = sizeof(DIPROPRANGE);
range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
range.diph.dwObj = pInstance->dwType; // ボタンやスティックのデータ
range.diph.dwHow = DIPH_BYID; // タイプで取得することを指定
range.lMin = -10; // 値の最小値
range.lMax = +10; // 値の最大値
LPDIRECTINPUTDEVICE8 pInputDev = (LPDIRECTINPUTDEVICE8)pvRef;
pInputDev->SetProperty(DIPROP_RANGE, &range.diph);
return DIENUM_CONTINUE;
}
BYTE CInput::GetPovPosition()
{
// デジタル入力から判断
switch(paddata.rgdwPOV[0]){
/* 省略 */
}
// アナログ入力から判断
BYTE result = 0x0;
if(paddata.lX > 5) result |= PP_RIGHT;
else if(paddata.lX < -5) result |= PP_LEFT;
if(paddata.lY > 5) result |= PP_DOWN;
else if(paddata.lY < -5) result |= PP_UP;
return result;
}
void CShip::Exec()
{
BYTE pos = input->GetPovPosition();
if(input->IsKeyDown(DIK_LEFT) || (pos & PP_LEFT)){
x -= 1.0f;
sprite.SetFrame(0);
}else if(input->IsKeyDown(DIK_RIGHT) || (pos & PP_RIGHT)){
x += 1.0f;
sprite.SetFrame(2);
}else{
sprite.SetFrame(1);
}
if(input->IsKeyDown(DIK_UP) || (pos & PP_UP)) y -= 1.0f;
if(input->IsKeyDown(DIK_DOWN) || (pos & PP_DOWN)) y += 1.0f;
if(input->IsKeyPressed(DIK_SPACE) || input->IsButtonPressed(0)){
// ミサイル発射
AppendObject(new CShoot(), 900, true);
}
sprite.Draw(x, y);
}