Home | Lesson | Game | Tool | Link

A05.ジョイパッド

2008/03/02:JOYINFOEXを使用するように変更
mmsystemを使用して、ジョイパッドの情報を取得します。
ジョイパッドが使えるようになると、複雑な操作も簡単にできるようになります。
ここでは、各ボタンの値などを紹介します。

PlayStation2用コントローラーをUSB接続して確認しています。
他のコントローラーの場合や、設定次第では取得する値が異なる場合があります。



ヘッダファイル追加
winmm.hとそのライブラリのwinmm.libを追加しておきます。
#ifdef WIN32
	#include <windows.h>
	#include <mmsystem.h>
	#pragma comment(lib, "winmm.lib")
	#pragma comment(lib, "Irrlicht.lib")
#endif

ジョイスティック設定
以下の方法でジョイスティックが使用可能か調べます。
1.デバイスの数を取得します。
 取得できない場合はデバイスエラーとなります。
2.ジョイスティックの接続状態を取得します。
 接続されていない場合はエラーとなります。
※ジョイスティックの情報を取得する構造体としてJOYINFOとJOYINFOEXの2つがあります。
 JOYINFOEXの方がより詳細情報を取得できるので、こちらを使用していきます。
 また、JOYINFOEXでは取得したい情報に制限をかけられるので、制限をかけずに
 全ての情報を取得できるように指定します。
 JOYINFOだと、ANALOG時の十字キーと、右スティックの上下情報を取得できません。

	//ジョイスティック設定
	JOYINFOEX joyinfo;
	MMRESULT result;
	int pos;
	if(joyGetNumDevs() == 0)
		return -1;//デバイスなし
	if(joyGetPosEx(JOYSTICKID1, &joyinfo) == JOYERR_UNPLUGGED)
		return -2;//接続なし

	//一応取得する情報をセット
	joyinfo.dwSize    = sizeof (JOYINFOEX);
	joyinfo.dwFlags   = JOY_RETURNALL;

フォント設定
状態表示用のフォントを設定します。
	//フォント設定
	IGUIEnvironment *Env = device->getGUIEnvironment(); 
	IGUIFont* Font = Env->getFont("font.bmp");
	unsigned short mess[32];

状態表示
ジョイパッドの状態を表示します。

基本操作は以下のようになります。
ANALOGスイッチOFF時
 十字キー      :左右でdwXpos/上下でdwYposが変化します。
 十字キー以外のボタン:dwButtonsが変化します。
 アナログスティック左:反応なし
 アナログスティック右:反応なし

ANALOGスイッチON時
 十字キー      :dwPOVが変化します。(そのまま使用するのは難しいので調整必要)
 十字キー以外のボタン:dwButtonsが変化します。
 アナログスティック左:左右でdwXpos/上下でdwYposが変化します。
 アナログスティック右:左右でdwZpos/上下はdwRposが変化します。

各ボタンの対応ビット
 △    :0x0001
 ○    :0x0002
 ×    :0x0004
 □    :0x0008
 L2    :0x0010
 R2    :0x0020
 L1    :0x0040
 R1    :0x0080
 START :0x0100
 SELECT:0x0200
 L3    :0x0400(ANALOG ON時のみ)
 R3    :0x0800(ANALOG ON時のみ)
 ANALOG:アナログのON/OFFを切り替えるだけで、値はありません

十字キー(ANALOGスイッチOFF時)
 左  :dwXpos = 0x0000、dwPOV = 0xFFFF
 右  :dwXpos = 0xFFFF、dwPOV = 0xFFFF
 上  :dwYpos = 0x0000、dwPOV = 0xFFFF
 下  :dwYpos = 0xFFFF、dwPOV = 0xFFFF

十字キー(ANALOGスイッチON時)
 左  :dwXpos = 0x????、dwPOV = 0x6978(27000)
 右  :dwXpos = 0x????、dwPOV = 0x2328( 9000)
 上  :dwYpos = 0x????、dwPOV = 0x0000(    0)
 下  :dwYpos = 0x????、dwPOV = 0x4650(18000)
 ※dwXposとdwYposは、左スティックの情報により変化するため測定不能

アナログスティック
 左(左右):dwXposに倒した値が影響
       中央値(触っていない場合)0x8000付近
       左に倒すほど0x0000に近づく
       右に倒すほど0xFFFFに近づく
 左(上下):dwYposに倒した値が影響
       中央値(触っていない場合)0x8000付近
       上に倒すほど0x0000に近づく
       下に倒すほど0xFFFFに近づく
 右(左右):dwZposに倒した値が影響
       中央値(触っていない場合)0x8000付近
       左に倒すほど0x0000に近づく
       右に倒すほど0xFFFFに近づく
 右(上下):dwRposに倒した値が影響
       中央値(触っていない場合)0x8000付近
       上に倒すほど0x0000に近づく
       下に倒すほど0xFFFFに近づく

※スティックは触っていない場合は0x8000付近の値を指します。
 ある程度の誤差があるため、0x8000を下回ったから特定のアクションを
 というのは止めたほうがよいでしょう。
 ある程度の余裕を持たせて(±0x2000くらい)、アクションを起こしましょう。
	while(device->run())
	{
		driver->beginScene(true,true,0xFF6060FF);

		result = joyGetPosEx(JOYSTICKID1, &joyinfo);
		if(result == JOYERR_NOERROR)
		{
			swprintf(mess, 32, L"dwButtons:%d", joyinfo.dwButtons);
			Font->draw(mess,rect<s32>(0,0,0,0),0xFFFFFFFF);    
			swprintf(mess, 32, L"dwXpos   :0x%04X", joyinfo.dwXpos);
			Font->draw(mess,rect<s32>(0,16,0,0),0xFFFFFFFF);    
			swprintf(mess, 32, L"dwYpos   :0x%04X", joyinfo.dwYpos);
			Font->draw(mess,rect<s32>(0,32,0,0),0xFFFFFFFF);    
			swprintf(mess, 32, L"dwZpos   :0x%04X", joyinfo.dwZpos);
			Font->draw(mess,rect<s32>(0,48,0,0),0xFFFFFFFF);    
		}

			//ANALOGモードでの方向キー
			pos = 0x00;//CENTER
			if(joyinfo.dwPOV != JOY_POVCENTERED )
			{
				if((joyinfo.dwPOV > JOY_POVLEFT)
					|| (joyinfo.dwPOV < JOY_POVRIGHT) )
				{
					pos |= 0x01;//UP
				}
				if((joyinfo.dwPOV > JOY_POVFORWARD)
					&& (joyinfo.dwPOV < JOY_POVBACKWARD) )
				{
					pos |= 0x02;//RIGHT
				}
				if((joyinfo.dwPOV > JOY_POVRIGHT) 
					&& (joyinfo.dwPOV < JOY_POVLEFT) )
				{
					pos |= 0x04;//DOWN
				}
				if(joyinfo.dwPOV > JOY_POVBACKWARD)
				{
					pos |= 0x08;//LEFT
				}
			}
			swprintf(mess, 32, L"dwPOV    :0x%04X", pos);
			Font->draw(mess,rect(0,80,0,0),0xFFFFFFFF); 

			swprintf(mess, 32, L"dwSize   :0x%04X", joyinfo.dwSize);
			Font->draw(mess,rect(0,96,0,0),0xFFFFFFFF); 

			swprintf(mess, 32, L"dwFlags  :0x%04X", joyinfo.dwFlags);
			Font->draw(mess,rect(0,112,0,0),0xFFFFFFFF); 

			swprintf(mess, 32, L"dwNum    :0x%04X", joyinfo.dwButtonNumber);
			Font->draw(mess,rect(0,128,0,0),0xFFFFFFFF);

		//シーンの描画
		smgr->drawAll();

		driver->endScene();
	}


アナログスティック
アナログスティックを使用すると、次のようなことができます。
・360度動かせるのを利用して、3D空間での視界確認
・倒し幅を利用して、少し倒した時は歩き、大きく倒した時は走る
・倒しても戻るのを利用して、ボールをはじくなどのアクション
ほかにも色々あるので、有効に使っていきましょう。


メモ
ここでは、PlayStation2用のコントローラーで解説していますが、
他のコントローラーを使用した場合は挙動が異なる場合があるので、注意して下さい。
PlayStation3のコントローラーだとボタンの番号が異なっていたり、
コントローラーの名前が異なっているようです。
どのコントローラーでも対応できるような「コンフィグ画面」を用意して
ユーザーが使い易い環境に変更させるのも必要になるでしょう。

オープンソースのSDLの中身を覗いてみると、MacやLinuxでの操作方法も載っています。
Windows以外の環境の人は、一度SDLの中身を見てみるのもよいでしょう。

ダウンロード
今回作成したファイル一式です。

宿題
1.SDLを見て、MacやLinuxでもジョイパッドが使えるようにしてみましょう。