★ DirectX Class ★ * Chapter 15: アナログスティックの利用 *
< アナログスティック入力の処理 >
わざわざ一章取る程の必要もない気はするのですが、アナログスティックの入力です。
実は前回まで解説で設定は終了しています。
< アナログ入力の取得 >
アナログ入力の取得も実は前回と同じコードでOKです。
では一体どこにアナログ入力の値があるのかというと、
DIJOYSTATE構造体のメンバlX及びlYです。
設定で最大値と最小値を設定しましたが、このlXとlYにそれぞれ最小値~最大値の値が入ります。
例えば、アナログスティックを半分くらい左に倒した場合、lXには『 -500 』前後の数値が入ります。
左へ完全に倒した場合、最小値である『 -1000 』が入ります。
ニュートラルのときは『 0 』が入ります。
まぁ数値で表されるとデジタルな気もしますが、あの小さなスティックの少しの傾きを1000分割するわけですから、
プレイヤー的にはほぼアナログでしょう。
そもそも数値にしないと、コンピュータでは処理できませんので。
< 入力受付の開始・終了/DirectInputの開放処理 >
キーボードのときと全く同じです。
< サンプル >
前回とほぼ変わらないコードで、取得したデータの表示を変えるだけではあんまりですので、
今回はDirect3Dと併用して、入力に応じてものを動かすことにしました。
左上に現在のスティックの状態が数値で表示され、真ん中にスティックの倒し具合が『 * 』で表示されます。

コードがずいぶんと長くなった気はしますが、Direct3Dについては第5章のものをほとんどコピーして使っています。

ポイントはピンク色で示してあります。

//-----------------------------------------------------------------
//
//    DirectInput Sample Program.
//
//-----------------------------------------------------------------
#define INITGUID

#define sqrtf sqrt
#define sinf  sin
#define cosf  cos
#define tanf  tan

#include <stdio.h>
#include <windows.h>

#include <d3d9.h>
#include <d3dx9.h>

#include <dinput.h>
#include <dinputex.h>

#pragma comment( lib , "d3d9.dll" );
#pragma comment( lib , "d3dx9.dll" );

#pragma comment( lib , "dinput8.dll" )



//-----------------------------------------------------------------
//    Grobal Variables.
//-----------------------------------------------------------------
LPDIRECTINPUT8       g_lpDI       = NULL;
LPDIRECTINPUTDEVICE8 g_lpDIDevice = NULL;
DIDEVCAPS            g_diDevCaps;

LPDIRECT3D9          g_pD3D       = NULL;
LPDIRECT3DDEVICE9    g_pd3dDevice = NULL;
LPD3DXFONT           g_pFont      = NULL;



//-----------------------------------------------------------------
//    Prototypes.
//-----------------------------------------------------------------
HWND    InitApp( HINSTANCE , int );
BOOL    InitDirectInput( HWND );
BOOL    ReadInput();
BOOL    CleanupDirectInput();
LRESULT CALLBACK WndProc( HWND , UINT , WPARAM , LPARAM );
BOOL    CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* , VOID* );
BOOL    CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* , VOID* );

BOOL    InitDirect3D( HWND );
BOOL    CleanupDirect3D();



//-----------------------------------------------------------------
//    Main.
//-----------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst , HINSTANCE hPrevinst , LPSTR nCmdLine , int nCmdShow )
{
	MSG  msg;
	HWND hWnd;
	
	hWnd = InitApp( hInst , nCmdShow );
	if ( !hWnd ) return FALSE;
	
	if ( !InitDirect3D( hWnd ) ) return FALSE;
	
	if ( !InitDirectInput( hWnd ) ) return FALSE;
	
	while( msg.message != WM_QUIT ){
		if ( PeekMessage( &msg , NULL , 0 , 0 , PM_REMOVE ) ){
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}else{
			ReadInput();
		}
		Sleep( 1 );
	}
	
	return msg.wParam;
}



//-----------------------------------------------------------------
//    Initialize Application.
//-----------------------------------------------------------------
HWND InitApp( HINSTANCE hInst , int nCmdShow )
{
	WNDCLASS wc;
	HWND hWnd;
	char szClassName[] = "DirectInput Test";
	
	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.hInstance     = hInst;
	wc.hCursor       = LoadCursor( NULL , IDC_ARROW );
	wc.hIcon         = LoadIcon( NULL , IDI_APPLICATION );
	wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpszClassName = szClassName;
	wc.lpszMenuName  = NULL;
	wc.lpfnWndProc   = WndProc;
	wc.cbWndExtra    = 0;
	wc.cbClsExtra    = 0;
	if ( !RegisterClass( &wc ) ) return FALSE;
	
	hWnd = CreateWindow( szClassName , "Direct3D Test" , WS_OVERLAPPEDWINDOW ,
	                     CW_USEDEFAULT , CW_USEDEFAULT , 640 , 480,
	                     NULL , NULL , hInst , NULL );
	if ( !hWnd ) return FALSE;
	
	ShowWindow( hWnd , nCmdShow );
	UpdateWindow( hWnd );
	
	return hWnd;
}



//-----------------------------------------------------------------
//    Initialize DirectInput.
//-----------------------------------------------------------------
BOOL InitDirectInput( HWND hWnd )
{
	HINSTANCE hInst;
	HRESULT   hr;
	
	hInst = (HINSTANCE)GetWindowLong( hWnd , GWL_HINSTANCE );
	
	hr = DirectInput8Create( hInst , DIRECTINPUT_VERSION , IID_IDirectInput8 ,
	                         (void**)&g_lpDI , NULL );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't create DirectInput object." , "Error" , MB_OK );
		return FALSE;
	}
	
	hr = g_lpDI->EnumDevices( DI8DEVCLASS_GAMECTRL , EnumJoysticksCallback ,
	                        NULL , DIEDFL_ATTACHEDONLY );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't create Device." , "Error" , MB_OK );
		return FALSE;
	}
	
	hr = g_lpDIDevice->SetDataFormat( &c_dfDIJoystick );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't set data format." , "Error" , MB_OK );
		return FALSE;
	}
	
	hr = g_lpDIDevice->SetCooperativeLevel( hWnd , DISCL_EXCLUSIVE | DISCL_FOREGROUND );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't set cooperative level." , "Error" , MB_OK );
		return FALSE;
	}
	
	g_diDevCaps.dwSize = sizeof( DIDEVCAPS );
	hr = g_lpDIDevice->GetCapabilities( &g_diDevCaps );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't create device capabilities." , "Error" , MB_OK );
		return FALSE;
	}
	
	hr = g_lpDIDevice->EnumObjects( EnumAxesCallback , (VOID*)hWnd , DIDFT_AXIS );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't set property." , "Error" , MB_OK );
		return FALSE;
	}
	
	hr = g_lpDIDevice->Poll();
	if ( FAILED( hr ) ){
		hr = g_lpDIDevice->Acquire();
		while( hr == DIERR_INPUTLOST ){
			hr = g_lpDIDevice->Acquire();
		}
	}
	
	return TRUE;
}



//------------------------------------------------------------------------------
//    Joysticks Callback.
//------------------------------------------------------------------------------
BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE *pdidInstance , VOID *pContext )
{
	HRESULT hr;
	
	hr = g_lpDI->CreateDevice( pdidInstance->guidInstance , &g_lpDIDevice , NULL );
	
	if ( FAILED( hr ) ) return DIENUM_CONTINUE;
	
	return DIENUM_STOP;
}



//------------------------------------------------------------------------------
//    Axes Callback.
//------------------------------------------------------------------------------
BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE *pdidoi , VOID *pContext )
{
	HRESULT     hr;
	DIPROPRANGE diprg;
	
	diprg.diph.dwSize       = sizeof( DIPROPRANGE );
	diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER );
	diprg.diph.dwHow        = DIPH_BYID;
	diprg.diph.dwObj        = pdidoi->dwType;
	diprg.lMin              = 0 - 1000;
	diprg.lMax              = 0 + 1000;
	hr = g_lpDIDevice->SetProperty( DIPROP_RANGE , &diprg.diph );
	
	if ( FAILED( hr ) ) return DIENUM_STOP;
	
	return DIENUM_CONTINUE;
}



//-----------------------------------------------------------------
//    Cleanup DirectInput.
//-----------------------------------------------------------------
BOOL CleanupDirectInput()
{
	g_lpDIDevice->Unacquire();
	
	if ( g_lpDIDevice != NULL )
		g_lpDIDevice->Release();
	
	if ( g_lpDI != NULL )
		g_lpDI->Release();
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Initialize Direct3D.
//-----------------------------------------------------------------
BOOL InitDirect3D( HWND hWnd )
{
	D3DPRESENT_PARAMETERS d3dpp;
	HRESULT hr;
	
	if ( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ){
		MessageBox( hWnd , "Can't create Direct3D." , "Error" , MB_OK );
		return FALSE;
	}
	ZeroMemory( &d3dpp , sizeof( d3dpp ) );
	d3dpp.Windowed         = TRUE;
	d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	
	hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
	                           D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
	                           &d3dpp , &g_pd3dDevice );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't create device." , "Error" , MB_OK );
		return FALSE;
	}
	
	D3DXCreateFont( g_pd3dDevice , 16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , "Times New Roman" , &g_pFont );
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Cleanup Direct3D.
//-----------------------------------------------------------------
BOOL CleanupDirect3D()
{
	if ( g_pFont != NULL )
		g_pFont->Release();
	
	if ( g_pd3dDevice != NULL )
		g_pd3dDevice->Release();
	
	if ( g_pD3D != NULL )
		g_pD3D->Release();
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Window Proc.
//-----------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd , UINT msg , WPARAM wp , LPARAM lp )
{
	switch( msg ){
		case WM_DESTROY:
			CleanupDirect3D();
			CleanupDirectInput();
			PostQuitMessage( 0 );
			break;
		default:
			return DefWindowProc( hWnd , msg , wp , lp );
	}
	
	return 0L;
}



//-----------------------------------------------------------------
//    Read Input.
//-----------------------------------------------------------------
BOOL ReadInput()
{
	DIJOYSTATE js;
	HRESULT    hr;
	
	RECT        rc;
	D3DXVECTOR3 center;
	char        buf[32];
	
	if ( NULL == g_lpDIDevice ) return FALSE;
	
	hr = g_lpDIDevice->Poll();
	if ( FAILED( hr ) ) return FALSE;
	
	hr = g_lpDIDevice->GetDeviceState( sizeof( DIJOYSTATE ) , &js );
	if ( FAILED( hr ) ) return FALSE;
	
	g_pd3dDevice->Clear( 0 , NULL , D3DCLEAR_TARGET ,
	                     0x00000000 , 1.0f , 0 );
	
	g_pd3dDevice->BeginScene();
	
	rc.left   = 320 + ( js.lX / 10 );
	rc.top    = 240 + ( js.lY / 10 );
	rc.right  = rc.left + 16;
	rc.bottom = rc.top  + 16;
	g_pFont->DrawText( NULL , "*" , -1 , &rc , NULL , 0xFFFF88FF );
	
	rc.left   = 10;
	rc.top    = 10;
	rc.right  = 640;
	rc.bottom = 40;
	sprintf( buf , "X = %6d , Y = %6d" , js.lX , js.lY );
	g_pFont->DrawText( NULL , buf , -1 , &rc , NULL , 0xFF66FFFF );
	
	g_pd3dDevice->EndScene();
	
	g_pd3dDevice->Present( NULL , NULL , NULL , NULL );
	
	return TRUE;
	
	return TRUE;
}

実行結果

クリックすると実物大で表示されます。
執筆: 2009/07/21 (TUE)