ジョイパッドの入力状態を取得するプログラム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ジョイパッドの入力状態を取得するプログラム

#31

投稿記事 by softya(ソフト屋) » 13年前

Xbox360コントローラならアナログ値をとれるのは、LRトリガーと2つのアナログスティックが取得出来ます。
LRトリガーは0 ~ 255、アナログスティックは -32768 ~ 32767の範囲の値です。
Windows用のゲームパッドでもアナログ値はありますよ。

今のプログラムは、強引にデジタル入力だけとして扱おうとしています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: ジョイパッドの入力状態を取得するプログラム

#32

投稿記事 by EKISUKE » 13年前

アナログとデジタルを分けるというイメージでやってみましたが、もう少し簡単にわけれそうですね・・・考え中です。

Controller.h

コード:

#pragma once
#pragma comment(lib,"XInput.lib")
#include <windows.h>
#include <Xinput.h>
class Controller
{
public:
    enum PAD_STATE{
        PAD_A = XINPUT_GAMEPAD_A,	//	Aボタン
        PAD_B = XINPUT_GAMEPAD_B,	//	Bボタン
        PAD_X = XINPUT_GAMEPAD_X,	//	Xボタン
        PAD_Y = XINPUT_GAMEPAD_Y,	//	Yボタン
		PAD_L_SHOULDER = XINPUT_GAMEPAD_LEFT_SHOULDER,  //	LB
		PAD_R_SHOULDER = XINPUT_GAMEPAD_RIGHT_SHOULDER,	//	RB
		PAD_BACK  = XINPUT_GAMEPAD_BACK,	//	Back
		PAD_START = XINPUT_GAMEPAD_START,	//	Start
		PAD_LEFT_THUMB  = XINPUT_GAMEPAD_LEFT_THUMB,	//	左スティック
		PAD_RIGHT_THUMB = XINPUT_GAMEPAD_RIGHT_THUMB,	//	右スティック
		PAD_LEFT_U_STICK,	//	左スティックの上
		PAD_LEFT_D_STICK,	//	左スティックの下
		PAD_LEFT_L_STICK,	//	左スティックの左
		PAD_LEFT_R_STICK,	//	左スティックの右
		PAD_RIGHT_U_STICK,	//	右スティックの上
        PAD_RIGHT_D_STICK,	//	右スティックの下
		PAD_RIGHT_L_STICK,	//	右スティックの左
        PAD_RIGHT_R_STICK,	//	右スティックの右
        PAD_L_TRIGGER,	//	左トリガー
		PAD_R_TRIGGER,	//	右トリガー
        PAD_UP		= XINPUT_GAMEPAD_DPAD_UP,	//	十字キーの上
		PAD_DOWN	= XINPUT_GAMEPAD_DPAD_DOWN,	//	十字キーの下
		PAD_LEFT	= XINPUT_GAMEPAD_DPAD_LEFT,	//	十字キーの左
		PAD_RIGHT	= XINPUT_GAMEPAD_DPAD_RIGHT,//	十字キーの右
    };
	enum INPUT_MODE{
		DIGITAL,
		ANALOG,
	};
public:
    Controller(int playerNum);
    bool GetPadState(PAD_STATE p_state, INPUT_MODE mode);
private :
	int _controllerNum;
};
Controller.cpp

コード:

#include "Controller.h"

Controller::Controller(int playerNum)
{
	_controllerNum = playerNum -1;
}

bool Controller::GetPadState(PAD_STATE p_state, INPUT_MODE mode)
{
	// 範囲指定用
	int L_TRIGGER_DEADZONE = 100;
	int R_TRIGGER_DEADZONE = 100;
	int L_STICK_THUMB_DEAD = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
	int R_STICK_THUMB_DEAD = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;

	XINPUT_STATE state;	// コントローラ情報取得用
    ZeroMemory( &state, sizeof(XINPUT_STATE) );	// 初期化
    DWORD dwResult;	// 関数結果判定用
	// 情報取得
    dwResult = XInputGetState(_controllerNum,&state);
    if(dwResult == ERROR_SUCCESS){
		switch(mode){
		case DIGITAL:
			if(state.Gamepad.wButtons & p_state){return true;}
			break;
		case ANALOG:
			if(p_state == PAD_L_TRIGGER){
				if(state.Gamepad.bLeftTrigger > L_TRIGGER_DEADZONE){return true;}
				break;
			}else if(p_state == PAD_R_TRIGGER){
				if(state.Gamepad.bRightTrigger > R_TRIGGER_DEADZONE){return true;}	
				break;
			}else if(p_state == PAD_LEFT_U_STICK){
				if(state.Gamepad.sThumbLY >  L_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_LEFT_D_STICK){
				if(state.Gamepad.sThumbLY < -L_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_LEFT_R_STICK){
				if(state.Gamepad.sThumbLX >  L_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_LEFT_L_STICK){
				if(state.Gamepad.sThumbLX <  -L_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_RIGHT_U_STICK){
				if(state.Gamepad.sThumbRY >   R_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_RIGHT_D_STICK){
				if(state.Gamepad.sThumbRY <  -R_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_RIGHT_R_STICK){
				if(state.Gamepad.sThumbRX >   R_STICK_THUMB_DEAD ){return true;}
				break;
			}else if(p_state == PAD_RIGHT_L_STICK){
				if(state.Gamepad.sThumbRX <  -R_STICK_THUMB_DEAD ){return true;}
				break;
			}
			break;
		}
	}
	return false;
}
main.cpp

コード:

#include "Controller.h"
#include <iostream>
using namespace std;
Controller* control;

int main()
{
	
	control = new Controller(1);
	while(true)
	{	
		if(control->GetPadState(control->PAD_LEFT_D_STICK, control->ANALOG))
		{cout<<"左スティックの下が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_U_STICK, control->ANALOG))
		{cout<<"左スティックの上が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_L_STICK, control->ANALOG))
		{cout<<"左スティックの左が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_R_STICK, control->ANALOG))
		{cout<<"左スティックの右が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_L_TRIGGER, control->ANALOG))
		{cout<<"左トリガー押されました。"<<endl;}
		if(control->GetPadState(control->PAD_R_TRIGGER, control->ANALOG))
		{cout<<"右トリガー押されました。"<<endl;}
		if(control->GetPadState(control->PAD_A, control->DIGITAL))
		{cout<<"Aボタンが押されました。"<<endl;}
	
		if(GetKeyState(VK_ESCAPE) & 0x80 )
		{
			break;
		}
	}
	return 0;
}
Controller側のソースは短くなったのですが、逆に呼び出しの引数が2つになり、メイン側の呼び出しの楽差がなくなってしまっているので、
どうやって引数を一つで、まとめれるかを考え中です。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ジョイパッドの入力状態を取得するプログラム

#33

投稿記事 by softya(ソフト屋) » 13年前

(1)アナログ入力をデジタルのように使いたいのなら使うときに引数でアナログを意識するもは面倒なだけです。
(2)アナログ入力はアナログで使いたいのならアナログ値を返さないとダメです。
つまり、(1)でも(2)でも無くどっちつかずだと思います。
ちなみに、(2)を共通のメンバ関数で実現するには無理があるので止めて下さい。

クラス側の都合が使うときに意識されると言うことは、クラスが抽象化の役割を果たしていないことになります。
XInputをわざわざクラスで包み隠しているのですから、XInputをそのまま使ったほうが分かりやすいというような事態は避けなければ行けません。
何のためのクラスなのかをよく考えてみて下さい。

※ だからと言ってクラスの1メンバ関数のコードが長くなるのは避けてくださいね。privateなメンバ関数も使い関数分割をしましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: ジョイパッドの入力状態を取得するプログラム

#34

投稿記事 by ISLe » 13年前

Xbox360のコントローラーに対応したプログラムでPS3のコントローラーを使いたいとき、PS3のコントローラーでXbox360のコントローラーを操作して、その入力を受け取るようにしたらプログラムを変更しなくて済みます。

Aボタンしか必要のないゲームでは、Aボタンしかないコントローラーを前提に作ればプログラムがシンプルになります。
実際に押されたのが何のボタンでも(あるいはボタンでなくても)、プログラムからはAボタンが押されたように見えれば良いわけです。

EKISUKE
記事: 108
登録日時: 13年前

Re: ジョイパッドの入力状態を取得するプログラム

#35

投稿記事 by EKISUKE » 13年前

GetPadStateのなかを関数で分け、アナログとデジタルをそれぞれ関数を持つようにしてみました。

Controller.h

コード:

#pragma once
#pragma comment(lib,"XInput.lib")
#include <windows.h>
#include <Xinput.h>
class Controller
{
public:
    enum PAD_STATE{
        PAD_A = XINPUT_GAMEPAD_A,	//	Aボタン
        PAD_B = XINPUT_GAMEPAD_B,	//	Bボタン
        PAD_X = XINPUT_GAMEPAD_X,	//	Xボタン
        PAD_Y = XINPUT_GAMEPAD_Y,	//	Yボタン
		PAD_L_SHOULDER = XINPUT_GAMEPAD_LEFT_SHOULDER,  //	LB
		PAD_R_SHOULDER = XINPUT_GAMEPAD_RIGHT_SHOULDER,	//	RB
		PAD_BACK  = XINPUT_GAMEPAD_BACK,	//	Back
		PAD_START = XINPUT_GAMEPAD_START,	//	Start
		PAD_LEFT_THUMB  = XINPUT_GAMEPAD_LEFT_THUMB,	//	左スティック
		PAD_RIGHT_THUMB = XINPUT_GAMEPAD_RIGHT_THUMB,	//	右スティック
		PAD_LEFT_U_STICK,	//	左スティックの上
		PAD_LEFT_D_STICK,	//	左スティックの下
		PAD_LEFT_L_STICK,	//	左スティックの左
		PAD_LEFT_R_STICK,	//	左スティックの右
		PAD_RIGHT_U_STICK,	//	右スティックの上
        PAD_RIGHT_D_STICK,	//	右スティックの下
		PAD_RIGHT_L_STICK,	//	右スティックの左
        PAD_RIGHT_R_STICK,	//	右スティックの右
        PAD_L_TRIGGER,	//	左トリガー
		PAD_R_TRIGGER,	//	右トリガー
        PAD_UP		= XINPUT_GAMEPAD_DPAD_UP,	//	十字キーの上
		PAD_DOWN	= XINPUT_GAMEPAD_DPAD_DOWN,	//	十字キーの下
		PAD_LEFT	= XINPUT_GAMEPAD_DPAD_LEFT,	//	十字キーの左
		PAD_RIGHT	= XINPUT_GAMEPAD_DPAD_RIGHT,//	十字キーの右
    };
public:
    Controller(int playerNum);
    bool GetPadState(PAD_STATE p_state);
private :
	int _controllerNum;
	bool GetDigitalState(XINPUT_STATE state, PAD_STATE p_state);
	bool GetAnalogState(XINPUT_STATE state, PAD_STATE p_state);
};
Controller.cpp

コード:

#include "Controller.h"

Controller::Controller(int playerNum)
{
	_controllerNum = playerNum -1;
}

bool Controller::GetPadState(PAD_STATE p_state)
{
	XINPUT_STATE state;	// コントローラ情報取得用
    ZeroMemory( &state, sizeof(XINPUT_STATE) );	// 初期化
    DWORD dwResult;	// 関数結果判定用
	// 情報取得
    dwResult = XInputGetState(_controllerNum,&state);
    if(dwResult == ERROR_SUCCESS){
		if(GetDigitalState(state,p_state)){return true;}
		if(GetAnalogState(state,p_state)){return true;}
	}
	return false;
}

bool Controller::GetDigitalState(XINPUT_STATE state, PAD_STATE p_state)
{
	if(state.Gamepad.wButtons & p_state){return true;}
	return false;
}

bool Controller::GetAnalogState(XINPUT_STATE state, PAD_STATE p_state)
{
	// 範囲指定用
	int TRIGGER_DEADZONE = 100;
	int L_STICK_THUMB_DEAD = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
	int R_STICK_THUMB_DEAD = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
	switch(p_state){		
	case PAD_L_TRIGGER:
		if(state.Gamepad.bLeftTrigger > TRIGGER_DEADZONE){return true;}
		break;
	case PAD_R_TRIGGER:
		if(state.Gamepad.bRightTrigger > TRIGGER_DEADZONE){return true;}	
		break;
	case PAD_LEFT_U_STICK:
		if(state.Gamepad.sThumbLY >  L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_D_STICK:
		if(state.Gamepad.sThumbLY < -L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_R_STICK:
		if(state.Gamepad.sThumbLX >  L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_L_STICK:
		if(state.Gamepad.sThumbLX < -L_STICK_THUMB_DEAD ){
			return true;
		}
		break;
	case PAD_RIGHT_U_STICK:
		if(state.Gamepad.sThumbRY >  R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_D_STICK:
		if(state.Gamepad.sThumbRY < -R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_R_STICK:
		if(state.Gamepad.sThumbRX >  R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_L_STICK:
		if(state.Gamepad.sThumbRX < -R_STICK_THUMB_DEAD ){return true;}
		break;
	}
	return false;
}
質問なんですが、なぜアナログ値を返す必要があるのでしょうか?何に使うのですか?
あと、まだ(1)でも(2)でもない状態ですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ジョイパッドの入力状態を取得するプログラム

#36

投稿記事 by softya(ソフト屋) » 13年前

質問には作るクラスの用途が書いていないので確認したいんです。
3DのFPSなどを作るならアナログ入力は必須で2Dでもシューティングやアクションで照準用として使っているゲームなんかもありますよね。
それこそ、どうコントローラのクラスをmainなど呼び出し側から使うのかって事です。
今の時点で使わないし汎用的に後でも使えるようなクラスを目指さないなら必要無いわけです。

>あと、まだ(1)でも(2)でもない状態ですか?

(1)に隠蔽できたいと思いますよ。
それとパッドの有無を調べるメソッドも必要だと思いますが如何でしょう?

【補足】
気になるといえばenum の定義が一貫性に掛けててバグりそうな予感がする事とそれに関連して
if(GetDigitalState(state,p_state)){return true;}
if(GetAnalogState(state,p_state)){return true;}
の分岐方法がビットパターンによってバグになる気がするんですが確かめられてますか?

【さらに補足】
上でISLeさんがPSパッドでも兼用する事を書いてますが、このクラスをどう使うか決めるのはEKISUKEさんなんです。
なのでしっかりクラスの設計コンセプトを決めてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: ジョイパッドの入力状態を取得するプログラム

#37

投稿記事 by EKISUKE » 13年前

softya(ソフト屋) さんが書きました:質問には作るクラスの用途が書いていないので確認したいんです。
3DのFPSなどを作るならアナログ入力は必須で2Dでもシューティングやアクションで照準用として使っているゲームなんかもありますよね。
それこそ、どうコントローラのクラスをmainなど呼び出し側から使うのかって事です。
今の時点で使わないし汎用的に後でも使えるようなクラスを目指さないなら必要無いわけです。
このプログラムを何に使うかと言いますと、学校の制作展に使います。
最近企画変更があり、コントローラーを使うということは決まっているのですが、
操作方法も詳しく決まっていないので、サンプルプログラムでも組んでみようと思って質問させていただいました。
今後コントローラーを使うゲームを作るとき、このソースコードを持っていくだけで出来ればいいと思っていますが、
他にも今取り組んでいる制作展で、やることはあるはずなので、そちらを優先しようと思っています。
なので、今回はアナログ値を返すプログラムはやめておきます。また、必要になった時に悩んだり、質問させていただくかと思います。
softya(ソフト屋) さんが書きました:(1)に隠蔽できたいと思いますよ。
それとパッドの有無を調べるメソッドも必要だと思いますが如何でしょう?
(2)にする場合どういうふうになったのでしょうか?教えていただければ幸いです。
softya(ソフト屋) さんが書きました:【補足】
気になるといえばenum の定義が一貫性に掛けててバグりそうな予感がする事とそれに関連して
if(GetDigitalState(state,p_state)){return true;}
if(GetAnalogState(state,p_state)){return true;}
の分岐方法がビットパターンによってバグになる気がするんですが確かめられてますか?
全部試してませんでした。十字キーなど色々バグがあったので、以下の様にしました。(長いです)

Controller.h

コード:

#pragma once
#pragma comment(lib,"XInput.lib")
#include <windows.h>
#include <Xinput.h>
class Controller
{
public:
    enum PAD_STATE{
		// デジタル
        PAD_A,	//	Aボタン
        PAD_B,	//	Bボタン
        PAD_X,	//	Xボタン
        PAD_Y,	//	Yボタン
		PAD_L_SHOULDER,  //	LB
		PAD_R_SHOULDER,	//	RB
		PAD_BACK,	//	Back
		PAD_START,	//	Start
        PAD_UP,		//	十字キーの上
		PAD_DOWN,	//	十字キーの下
		PAD_LEFT,	//	十字キーの左
		PAD_RIGHT,	//	十字キーの右
		PAD_LEFT_THUMB,		//	左スティック
		PAD_RIGHT_THUMB,	//	右スティック
		// アナログ
		PAD_LEFT_U_STICK,	//	左スティックの上
		PAD_LEFT_D_STICK,	//	左スティックの下
		PAD_LEFT_L_STICK,	//	左スティックの左
		PAD_LEFT_R_STICK,	//	左スティックの右
		PAD_RIGHT_U_STICK,	//	右スティックの上
        PAD_RIGHT_D_STICK,	//	右スティックの下
		PAD_RIGHT_L_STICK,	//	右スティックの左
        PAD_RIGHT_R_STICK,	//	右スティックの右
        PAD_L_TRIGGER,	//	左トリガー
		PAD_R_TRIGGER,	//	右トリガー
    };
	enum MODE{
		DIGITAL,
		ANALOG,
	};
public:
    Controller(int playerNum);
    bool IsConnected();
	bool GetPadState(PAD_STATE p_state);
private :
	int _controllerNum;
	MODE mode;
	bool GetDigitalState(XINPUT_STATE state, PAD_STATE p_state);
	bool GetAnalogState(XINPUT_STATE state, PAD_STATE p_state);
	void To_XInput(PAD_STATE &p_state);
	void CheckMode(PAD_STATE p_state);
};
Controller.cpp

コード:

#include "Controller.h"

Controller::Controller(int playerNum)
{
	_controllerNum = playerNum -1;
}

bool Controller::IsConnected()
{
	XINPUT_STATE state;	// コントローラ情報取得用
	// 初期化
	ZeroMemory( &state, sizeof(XINPUT_STATE) );

	// 状態取得
	DWORD Result = XInputGetState(_controllerNum, &state);

    if(Result == ERROR_SUCCESS){
        return true;	// 接続されています。
    }else{
        return false;	// 接続されていません。
    }
}


bool Controller::GetPadState(PAD_STATE p_state)
{
	XINPUT_STATE state;	// コントローラ情報取得用
    ZeroMemory( &state, sizeof(XINPUT_STATE) );	// 初期化
    DWORD dwResult;	// 関数結果判定用
	// 情報取得
    dwResult = XInputGetState(_controllerNum,&state);
    if(dwResult == ERROR_SUCCESS){
		CheckMode(p_state);
		switch(mode){
		case ANALOG:
			if(GetAnalogState(state,p_state)){return true;}
			break;
		case DIGITAL:
			if(GetDigitalState(state,p_state)){return true;}
			break;
		}
	}
	return false;
}

bool Controller::GetDigitalState(XINPUT_STATE state, PAD_STATE p_state)
{
	To_XInput(p_state);
	if(state.Gamepad.wButtons & p_state){return true;}
	return false;
}

bool Controller::GetAnalogState(XINPUT_STATE state, PAD_STATE p_state)
{
	// 範囲指定用
	int TRIGGER_DEADZONE = 100;
	int L_STICK_THUMB_DEAD = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
	int R_STICK_THUMB_DEAD = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
	switch(p_state){		
	case PAD_L_TRIGGER:
		if(state.Gamepad.bLeftTrigger > TRIGGER_DEADZONE){return true;}
		break;
	case PAD_R_TRIGGER:
		if(state.Gamepad.bRightTrigger > TRIGGER_DEADZONE){return true;}	
		break;
	case PAD_LEFT_U_STICK:
		if(state.Gamepad.sThumbLY >  L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_D_STICK:
		if(state.Gamepad.sThumbLY < -L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_R_STICK:
		if(state.Gamepad.sThumbLX >  L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_L_STICK:
		if(state.Gamepad.sThumbLX < -L_STICK_THUMB_DEAD ){
			return true;
		}
		break;
	case PAD_RIGHT_U_STICK:
		if(state.Gamepad.sThumbRY >  R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_D_STICK:
		if(state.Gamepad.sThumbRY < -R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_R_STICK:
		if(state.Gamepad.sThumbRX >  R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_L_STICK:
		if(state.Gamepad.sThumbRX < -R_STICK_THUMB_DEAD ){return true;}
		break;
	}
	return false;
}

void Controller::To_XInput(PAD_STATE &p_state)
{
	switch(p_state){
	case PAD_A:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_A;
		break;
	case PAD_B:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_B;
		break;
	case PAD_X:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_X;
		break;
	case PAD_Y:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_Y;
		break;
	case PAD_L_SHOULDER:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_LEFT_SHOULDER;
		break;
	case PAD_R_SHOULDER:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_RIGHT_SHOULDER;
		break;
	case PAD_BACK:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_BACK;
		break;
	case PAD_START:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_START;
		break;
	case PAD_UP:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_DPAD_UP;
		break;
	case PAD_DOWN:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_DPAD_DOWN;
		break;
	case PAD_LEFT:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_DPAD_LEFT;
		break;
	case PAD_RIGHT:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_DPAD_RIGHT;
		break;
	case PAD_LEFT_THUMB:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_LEFT_THUMB;
		break;
	case PAD_RIGHT_THUMB:
		p_state = (PAD_STATE)XINPUT_GAMEPAD_RIGHT_THUMB;
		break;
	}
}

void Controller::CheckMode(PAD_STATE p_state){
	switch(p_state){
	case PAD_LEFT_U_STICK:
	case PAD_LEFT_D_STICK:
	case PAD_LEFT_L_STICK:
	case PAD_LEFT_R_STICK:
	case PAD_RIGHT_U_STICK:
	case PAD_RIGHT_D_STICK:
	case PAD_RIGHT_L_STICK:
	case PAD_RIGHT_R_STICK:
	case PAD_L_TRIGGER:
	case PAD_R_TRIGGER:
		mode = ANALOG;	//	アナログモード
		break;
	default:
		mode = DIGITAL;	//	デジタルモード
		break;
	}
}
main.cpp

コード:

#include "Controller.h"
#include <iostream>
using namespace std;
Controller* control;

int main()
{
	
	control = new Controller(1);
	// 接続情報取得
	if(control->IsConnected()==false)
	{cout<<"コントローラーが接続されていません。"<<endl;}

	while(control->IsConnected())
	{	
		//---- スティック
		//---- 左
		if(control->GetPadState(control->PAD_LEFT_D_STICK))
		{cout<<"左スティックの下が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_U_STICK))
		{cout<<"左スティックの上が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_L_STICK))
		{cout<<"左スティックの左が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_R_STICK))
		{cout<<"左スティックの右が押されました。"<<endl;}
		//---- 右
		if(control->GetPadState(control->PAD_RIGHT_D_STICK))
		{cout<<"右スティックの下が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_RIGHT_U_STICK))
		{cout<<"右スティックの上が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_RIGHT_L_STICK))
		{cout<<"右スティックの左が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_RIGHT_R_STICK))
		{cout<<"右スティックの右が押されました。"<<endl;}
		
		//---- トリガー
		if(control->GetPadState(control->PAD_L_TRIGGER))
		{cout<<"左トリガー押されました。"<<endl;}
		if(control->GetPadState(control->PAD_R_TRIGGER))
		{cout<<"右トリガー押されました。"<<endl;}
		//---- ボタン
		if(control->GetPadState(control->PAD_A))
		{cout<<"Aボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_B))
		{cout<<"Bボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_X))
		{cout<<"Xボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_Y))
		{cout<<"Yボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_BACK))
		{cout<<"Backボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_START))
		{cout<<"Startボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT_THUMB))
		{cout<<"左スティックボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_RIGHT_THUMB))
		{cout<<"右スティックボタンが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_L_SHOULDER))
		{cout<<"LBが押されました。"<<endl;}
		if(control->GetPadState(control->PAD_R_SHOULDER))
		{cout<<"RBが押されました。"<<endl;}
		//---- 十字キー
		if(control->GetPadState(control->PAD_UP))
		{cout<<"十字キーの上が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_DOWN))
		{cout<<"十字キーの下が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_LEFT))
		{cout<<"十字キーの左が押されました。"<<endl;}
		if(control->GetPadState(control->PAD_RIGHT))
		{cout<<"十字キーの右が押されました。"<<endl;}
	
		if(GetKeyState(VK_ESCAPE) & 0x80 )
		{
			break;
		}
	}
	return 0;
}
まだプログラムとして、なにか指摘ありましたら、お願いします。
softya(ソフト屋) さんが書きました:【さらに補足】
上でISLeさんがPSパッドでも兼用する事を書いてますが、このクラスをどう使うか決めるのはEKISUKEさんなんです。
なのでしっかりクラスの設計コンセプトを決めてください。
そうですね、少し考えてみます。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ジョイパッドの入力状態を取得するプログラム

#38

投稿記事 by softya(ソフト屋) » 13年前

EKISUKE さんが書きました:(2)にする場合どういうふうになったのでしょうか?教えていただければ幸いです。
それがアナログ値を返すって事です。まぁメソッドを増やすことになるでしょう。
どう返すかは工夫の余地あるところですね。 → つまり使い方を想定してインターフェイス設計しないといけません。
EKISUKE さんが書きました:まだプログラムとして、なにか指摘ありましたら、お願いします。
To_XInput()とCheckMode()は配列を使うと短く出来るかもと言っておきます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: ジョイパッドの入力状態を取得するプログラム

#39

投稿記事 by EKISUKE » 12年前

返信遅くなりました。

今回はコントローラーの入力もとれ、どこに持って行ってもすぐにコントローラーが使えるようなソースファイルが作れました。
なので、解決とさせて頂きます。
コードの長さを短縮させる方法は今やっている他のことが落ち着いてから、考えてみます。
回答ありがとうございました。

EKISUKE
記事: 108
登録日時: 13年前

Re: ジョイパッドの入力状態を取得するプログラム

#40

投稿記事 by EKISUKE » 12年前

お久しぶりです。
すこしコントローラーの長かった部分を短縮してみました。
配列でのやり方が思い浮かばなかったので、違ったやり方ですが、これでできました。

Controller.h

コード:

class Controller
{
public:

	//! コマンド列挙体
	//@{
    enum PAD_STATE{
		// デジタル
		PAD_UP,		//	十字キーの上
		PAD_DOWN,	//	十字キーの下
		PAD_LEFT,	//	十字キーの左
		PAD_RIGHT,	//	十字キーの右
		PAD_START,	//	Start
		PAD_BACK,	//	Back
		PAD_LEFT_THUMB,		//	左スティック
		PAD_RIGHT_THUMB,	//	右スティック
		PAD_LB,  //	LB
		PAD_RB,	//	RB
        PAD_A,	//	Aボタン
        PAD_B,	//	Bボタン
        PAD_X,	//	Xボタン
        PAD_Y,	//	Yボタン
		// アナログ
		PAD_LEFT_U_STICK,	//	左スティックの上
		PAD_LEFT_D_STICK,	//	左スティックの下
		PAD_LEFT_L_STICK,	//	左スティックの左
		PAD_LEFT_R_STICK,	//	左スティックの右
		PAD_RIGHT_U_STICK,	//	右スティックの上
        PAD_RIGHT_D_STICK,	//	右スティックの下
		PAD_RIGHT_L_STICK,	//	右スティックの左
        PAD_RIGHT_R_STICK,	//	右スティックの右
        PAD_LT,	//	左トリガー
		PAD_RT,	//	右トリガー
    };
	//@}

	//!	入力モード
	//@{
	enum MODE{
		DIGITAL,
		ANALOG,
	};

	public:
	//!	コンストラクタ
    Controller(s32 playerNum);
	//!	接続確認関数
    bool IsConnected();
	//!	入力チェック関数
	bool GetPadState(PAD_STATE p_state);
	//!	振動
	void EnableVibration( f32 L_vib, f32 R_vib );
	void DisableVibration();

	
private :
	
	s32 _controllerNum;		//!<	接続コントローラー数
	MODE mode;				//!<	入力モード

	s32	XInputPadState[14]; //!<	XInputのパッドの列挙が入っている

	//! デジタルの入力チェック
	bool GetDigitalState(XINPUT_STATE state, PAD_STATE p_state);
	//!	アナログの入力チェック
	bool GetAnalogState(XINPUT_STATE state, PAD_STATE p_state);
	//!	XINPUTに変換
	void To_XInput(PAD_STATE &p_state);
	//!	入力モードチェック関数
	void CheckMode(PAD_STATE p_state);
};
Controller.cpp

コード:

//--------------------------------------------------------------
//!	コンストラクタ
//--------------------------------------------------------------
Controller::Controller(s32 playerNum)
{
	_controllerNum = playerNum -1;

	for( int i=0; i<16; i++ ){
		// 配列番号用の変数
		static int	Index = 0;

		if( i == 10 || i == 11 ){
			continue;
		}

		XInputPadState[Index] = 0x001 << i;

		// 次の番号へ
		Index++;
	}
}

//--------------------------------------------------------------
//!	接続確認
//--------------------------------------------------------------
bool Controller::IsConnected()
{
	XINPUT_STATE state;	// コントローラ情報取得用
	// 初期化
	ZeroMemory( &state, sizeof(XINPUT_STATE) );

	// 状態取得
	DWORD Result = XInputGetState(_controllerNum, &state);

    if(Result == ERROR_SUCCESS){
        return true;	// 接続されています。
    }else{
        return false;	// 接続されていません。
    }
}

//--------------------------------------------------------------
//!	入力チェック
//--------------------------------------------------------------
bool Controller::GetPadState(PAD_STATE p_state)
{
	XINPUT_STATE state;	// コントローラ情報取得用
    ZeroMemory( &state, sizeof(XINPUT_STATE) );	// 初期化
    DWORD dwResult;	// 関数結果判定用
	// 情報取得
    dwResult = XInputGetState(_controllerNum,&state);
    if(dwResult == ERROR_SUCCESS){	//	情報がとれたら
		CheckMode(p_state);	//	アナログモードかデジタルかチェック
		//	モードによって入力チェック切替
		switch(mode){
		case ANALOG:	//	アナログ
			if(GetAnalogState(state,p_state)){return true;}
			break;
		case DIGITAL:	//	デジタル
			if(GetDigitalState(state,p_state)){return true;}
			break;
		}
	}
	return false;
}

//--------------------------------------------------------------
//! デジタルの入力チェック
//--------------------------------------------------------------
bool Controller::GetDigitalState(XINPUT_STATE state, PAD_STATE p_state)
{
	To_XInput(p_state);	//	XINPUTに変換
	//	入力チェック
	if(state.Gamepad.wButtons & p_state){return true;}	
	return false;
}

//--------------------------------------------------------------
//!	アナログの入力チェック
//--------------------------------------------------------------
bool Controller::GetAnalogState(XINPUT_STATE state, PAD_STATE p_state)
{
	// トリガーの入力無視範囲設定
	int TRIGGER_DEADZONE = 100;
	//	スティックの入力無視判定設定
	int L_STICK_THUMB_DEAD = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
	int R_STICK_THUMB_DEAD = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;
	//	入力の状態によって入力チェック切替
	switch(p_state){
	//	トリガー
	case PAD_LT:
		if(state.Gamepad.bLeftTrigger > TRIGGER_DEADZONE){return true;}
		break;
	case PAD_RT:
		if(state.Gamepad.bRightTrigger > TRIGGER_DEADZONE){return true;}	
		break;
	//	左スティック
	case PAD_LEFT_U_STICK:
		if(state.Gamepad.sThumbLY >  L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_D_STICK:
		if(state.Gamepad.sThumbLY < -L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_R_STICK:
		if(state.Gamepad.sThumbLX >  L_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_LEFT_L_STICK:
		if(state.Gamepad.sThumbLX < -L_STICK_THUMB_DEAD ){return true;}
		break;
	//	右スティック
	case PAD_RIGHT_U_STICK:
		if(state.Gamepad.sThumbRY >  R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_D_STICK:
		if(state.Gamepad.sThumbRY < -R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_R_STICK:
		if(state.Gamepad.sThumbRX >  R_STICK_THUMB_DEAD ){return true;}
		break;
	case PAD_RIGHT_L_STICK:
		if(state.Gamepad.sThumbRX < -R_STICK_THUMB_DEAD ){return true;}
		break;
	}
	return false;
}

//--------------------------------------------------------------
//!	XINPUTに変換
//--------------------------------------------------------------
void Controller::To_XInput(PAD_STATE &p_state)
{
	//	入力状態によってその後の処理切替
	p_state = (PAD_STATE)XInputPadState[p_state];
}

//--------------------------------------------------------------
//!	入力モードチェック
//--------------------------------------------------------------
void Controller::CheckMode(PAD_STATE p_state){

	int stateNum	   = p_state;
	int LastDigitalNum = PAD_Y;

	if( stateNum > LastDigitalNum ){
		mode = ANALOG;
	}else{
		mode = DIGITAL;
	}

}

//--------------------------------------------------------------
//!	振動開始
//!	@param [in] L_vib	左振動値(0.0f ~ 1.0f)
//!	@param [in] R_vib	右振動値(0.0f ~ 1.0f)
//--------------------------------------------------------------
void Controller::EnableVibration( f32 L_vib, f32 R_vib )
{
	//	振動値を0.0~1.0fから 0 ~ 65535に変換
	L_vib = 65535 * L_vib;
	R_vib = 65535 * R_vib;
	//	振動用の構造体
	XINPUT_VIBRATION	vibration;
	//	初期化
	ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) );
	//	振動値代入
	vibration.wLeftMotorSpeed  = L_vib;
	vibration.wRightMotorSpeed = R_vib;
	//	結果転送
	XInputSetState( _controllerNum, &vibration);
}
//--------------------------------------------------------------
//!	振動停止
//--------------------------------------------------------------
void Controller::DisableVibration()
{
	//	振動用の構造体
	XINPUT_VIBRATION	vibration;
	//	初期化
	ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) );
	//	振動値代入
	vibration.wLeftMotorSpeed  = 0;
	vibration.wRightMotorSpeed = 0;
	//	結果転送
	XInputSetState( _controllerNum, &vibration);
}
XInputのボタンが10進数で10と11以外の時は16進数の0x001の左シフトでいけるようなのでそうしました。
そのため自前の列挙体もXInputと同じ並びにしました。

アナログかデジタルかは元の列挙体の並びをアナログとデジタルで分けているので、
デジタルの最後の列挙体の番号より大きければアナログ、そうでなければデジタルという分け方にしてみました。

すこしやり方が汚いと思うので、教えてほしいことがあります。

1 以前おっしゃっていた配列でのやり方というのはどのようなやり方なのでしょうか?
2 このやり方はプログラムとして悪いやり方ですか?

この2点を教えてください。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ジョイパッドの入力状態を取得するプログラム

#41

投稿記事 by softya(ソフト屋) » 12年前

前よりスッキリしたと思います。
これ以上は無理して縮める必要はないんじゃないでしょうか。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

“C言語何でも質問掲示板” へ戻る