コントローラの入力

2021年8月20日

SDLでコントローラの入力を取得するには、下記の関数を使用します。

SDL_NumJoysticks関数

接続したジョイスティックの数を取得します。

宣言

int SDL_NumJoysticks();

戻り値

「接続したジョイスティックの数」を返します。

SDL_IsGameController関数

ジョイスティックがゲームコントローラのインターフェースに対応しているか判別する値を取得します。

宣言

SDL_bool SDL_IsGameController( int joystick_index );

引数

joystick_indexジョイスティックの番号です。
※ この番号は0から順に数えます。

戻り値

「 ゲームコントローラのインターフェースに対応しているか判別する値 」を返します。

SDL_GameControllerOpen関数

ゲームコントローラを有効にします。

宣言

SDL_GameController* SDL_GameControllerOpen( int joystick_index );

引数

joystick_indexジョイスティックの番号です。

戻り値

有効化に成功すると「ゲームコントローラのアドレス」を返し、失敗すると「NULL」を返します。

SDL_GameControllerClose関数

ゲームコントローラを無効にします。

宣言

void SDL_GameControllerClose( SDL_GameController* gamecontroller );

引数

gamecontrollerゲームコントローラのアドレスです。

SDL_GameControllerGetButton関数

ゲームコントローラのボタンの状態を取得します。

宣言

Uint8 SDL_GameControllerGetButton( 
    SDL_GameController*         gamecontroller, 
    SDL_GameControllerButton    button
);

引数

gamecontroller ゲームコントローラのアドレスです。
buttonボタンの種類です。

戻り値

ボタンを押していると「1」を返し、押していないと「0」を返します。

SDL_GameControllerGetAxis関数

ゲームコントローラの軸の状態を取得します。

宣言

Sint16 SDL_GameControllerGetAxis( 
    SDL_GameController*     gamecontroller, 
    SDL_GameControllerAxis  axis 
);

引数

gamecontroller ゲームコントローラのアドレスです。
axis軸の種類です。

戻り値

軸の状態を表す数値を返します。この値は、-32768から32767までの数になります。

サンプルプログラム

#include <SDL.h>

SDL_Window*         g_window        = nullptr;
SDL_GameController* g_controller    = nullptr;

bool Initialize();
bool Update();
void Finalize();
void OnAddedController( int index );
void OnRemovedController();
void OutputControllerState();
void OutputIfButtonStateIsPushing( SDL_GameControllerButton type, const char name[] );
void OutputIfAxisStateIsTilting( SDL_GameControllerAxis type, const char name[] );

int main( int argc, char* argv[] ) 
{
    if ( !Initialize() )
    {
        Finalize();
        return -1;
    }

    while ( true )
    {
        if ( !Update() ) break;
    }

    Finalize();

    return 0;
}

bool Initialize() 
{
    if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER ) )
    {
        SDL_Log( u8"SDLの初期化処理に失敗しました。エラーメッセージ: %s", SDL_GetError() );
        return false;
    }

    g_window = SDL_CreateWindow(
        u8"サンプル",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        1280,
        720,
        0
    );

    if ( g_window == nullptr )
    {
        SDL_Log( u8"ウィンドウの作成に失敗しました。エラーメッセージ: %s", SDL_GetError() );
        return false;
    }

    for ( auto i = 0, joystick_count = SDL_NumJoysticks(); i < joystick_count; i++ )
    {
        if ( !SDL_IsGameController( i ) ) continue;

        g_controller = SDL_GameControllerOpen( i );
        if ( g_controller != nullptr ) break;

        SDL_Log( u8"コントローラを開くのに失敗しました。エラーメッセージ: %s", SDL_GetError() );
        return false;
    }

    return true;
}

bool Update() 
{
    auto is_continuing  = true;
    auto event_info     = SDL_Event();

    while ( SDL_PollEvent( &event_info ) == 1 )
    {
        switch ( event_info.type )
        {
        case SDL_QUIT:
            is_continuing = false;
            break;
        case SDL_CONTROLLERDEVICEADDED:
            OnAddedController( event_info.cdevice.which );
            if ( g_controller == nullptr ) is_continuing = false;
            break;
        case SDL_CONTROLLERDEVICEREMOVED:
            OnRemovedController();
            break;
        }
    }

    OutputControllerState();
    SDL_Delay( 33 );

    return is_continuing;
}

void Finalize() 
{
    if ( g_controller   != nullptr )    SDL_GameControllerClose( g_controller );
    if ( g_window       != nullptr )    SDL_DestroyWindow( g_window );
    SDL_Quit();
}

void OnAddedController( int index )
{
    if ( g_controller != nullptr ) return;
    g_controller = SDL_GameControllerOpen( index );

    if ( g_controller != nullptr ) return;
    SDL_Log( u8"コントローラを開くのに失敗しました。エラーメッセージ: %s", SDL_GetError() );
}

void OnRemovedController() 
{
    if ( g_controller == nullptr ) return;

    SDL_GameControllerClose( g_controller );
    g_controller = nullptr;
}

void OutputControllerState()
{
    if ( g_controller == nullptr ) return;

    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_A            , u8"A" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_B            , u8"B" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_X            , u8"X" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_Y            , u8"Y" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_BACK         , u8"バック" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_START        , u8"スタート" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_LEFTSTICK    , u8"左スティック" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_RIGHTSTICK   , u8"右スティック" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_LEFTSHOULDER , u8"左ショルダー" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, u8"右ショルダー" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_DPAD_UP      , u8"上" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_DPAD_DOWN    , u8"下" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_DPAD_LEFT    , u8"左" );
    OutputIfButtonStateIsPushing( SDL_CONTROLLER_BUTTON_DPAD_RIGHT   , u8"右" );

    OutputIfAxisStateIsTilting( SDL_CONTROLLER_AXIS_LEFTX       , u8"左スティックのX軸" );
    OutputIfAxisStateIsTilting( SDL_CONTROLLER_AXIS_LEFTY       , u8"左スティックのY軸" );
    OutputIfAxisStateIsTilting( SDL_CONTROLLER_AXIS_RIGHTX      , u8"右スティックのX軸" );
    OutputIfAxisStateIsTilting( SDL_CONTROLLER_AXIS_RIGHTY      , u8"右スティックのY軸" );
    OutputIfAxisStateIsTilting( SDL_CONTROLLER_AXIS_TRIGGERLEFT , u8"左トリガー" );
    OutputIfAxisStateIsTilting( SDL_CONTROLLER_AXIS_TRIGGERRIGHT, u8"右トリガー" );
}

void OutputIfButtonStateIsPushing( SDL_GameControllerButton type, const char name[] ) 
{
    if ( SDL_GameControllerGetButton( g_controller, type ) == 0 ) return;

    SDL_Log( u8"%sボタンを押しています。", name );
}

void OutputIfAxisStateIsTilting( SDL_GameControllerAxis type, const char name[] )
{
    auto value      = SDL_GameControllerGetAxis( g_controller, type );
    auto threshold  = 10000;
    
    if ( SDL_abs( value ) < threshold ) return;
    SDL_Log( u8"%sの値は%dです。", name, value );
}

参考ページ