【C++】SDL3だけでコントローラー全機種対応する方法を完全解説

サムネイル画像 C++

ゲーム開発で「特定のコントローラーでしか動かない」という悩みを抱えていませんか?XInputはXbox専用、DirectInputは古くて振動が使えない…そんな問題をSDL3だけで全機種対応できる方法を解説します。

SDL3とは?

SDL(Simple DirectMedia Layer)は、クロスプラットフォーム対応のマルチメディアライブラリです。SDL3はその最新版で、ゲームパッド・ジョイスティック・オーディオ・グラフィックスなどを統一APIで扱えます。

SDL3の主な特徴

  • 全機種対応: Xbox・PlayStation・Nintendo Switch・汎用コントローラーすべてに対応
  • クロスプラットフォーム: Windows・Mac・Linuxで同じコードが動作
  • 自動ボタンマッピング: 機種ごとのボタン配置を自動認識
  • 振動機能: SDL_RumbleGamepadで全機種対応の振動制御
  • オープンソース: zlibライセンスで商用利用可能

完全版のコードリポジトリ

今回解説するコードは、GitHubリポジトリで公開されています:

📁 GitHub: https://github.com/it-kashiros/controller_SDL

リポジトリには以下のファイルが含まれています:

  • game_controller.h — コントローラークラスのヘッダーファイル
  • game_controller.cpp — SDL3を使った実装
  • main.cpp — デバッグ用サンプルプログラム

これらのファイルをダウンロードして、自分のVisual Studioプロジェクトに追加してください。

SDL3のセットアップ手順

手順1: SDL3をダウンロード

  1. GitHub Releasesにアクセス: https://github.com/libsdl-org/SDL/releases
  2. 最新の SDL3-devel-x.x.x-VC.zip(Visual Studio用)をダウンロード
    x.x.xはバージョン番号(例: 3.2.0)
  3. .slnファイルと同じディレクトリに解凍(例: プロジェクトフォルダ直下にSDL3\フォルダができる)

手順2: Visual Studioのプロジェクト設定

  1. プロジェクトのプロパティを開く(Alt + F7)
  2. C/C++ → 全般 → 追加のインクルードディレクトリに以下を追加:
$(SolutionDir)SDL3\include
  1. リンカー → 全般 → 追加のライブラリディレクトリに以下を追加:
$(SolutionDir)SDL3\lib\x64

※ 32bit版を使う場合はx64x86に変更してください。

  1. リンカー → 入力 → 追加の依存ファイルに以下を追加:
SDL3.lib
  1. SDL3\lib\x64\SDL3.dllを、実行ファイル(.exe)と同じフォルダにコピー

※ DebugとRelease両方のフォルダにコピーしてください

実装の流れ

以下、主要な実装ポイントを解説します。

▼ game_controller.h

コントローラークラスのヘッダーファイルです。以下の構造体とクラスを定義しています:

#pragma once
#include <SDL3/SDL.h>

// コントローラーの状態を保持する構造体
struct GamepadState {
    float leftStickX, leftStickY;
    float rightStickX, rightStickY;
    float leftTrigger, rightTrigger;
    bool dpadUp, dpadDown, dpadLeft, dpadRight;
    bool buttonA, buttonB, buttonX, buttonY;
    bool isConnected;
};

// コントローラー管理クラス
class GameController {
public:
    static bool Initialize();
    static void Finalize();
    static void Update();
    static bool IsConnected();
    static float GetLeftStickX();
    static bool IsTrigger_ButtonA();
    static void StartVibration(float intensity, int duration_ms);
private:
    static SDL_Gamepad* s_gamepad;
    static GamepadState s_currentState;
};

▼ game_controller.cpp(抜粋)

初期化とコントローラー接続処理:

bool GameController::Initialize() {
    if (!SDL_Init(SDL_INIT_GAMEPAD)) {
        return false;
    }
    
    int count;
    SDL_JoystickID* ids = SDL_GetGamepads(&count);
    if (count > 0) {
        s_gamepad = SDL_OpenGamepad(ids[0]);
    }
    SDL_free(ids);
    return true;
}

ボタン入力の取得:

float GameController::GetLeftStickX() {
    if (!s_gamepad) return 0.0f;
    Sint16 value = SDL_GetGamepadAxis(s_gamepad, SDL_GAMEPAD_AXIS_LEFTX);
    return value / 32767.0f; // -1.0〜1.0に正規化
}

bool GameController::IsTrigger_ButtonA() {
    return s_currentState.buttonA && !s_prevState.buttonA;
}

振動機能:

void GameController::StartVibration(float intensity, int duration_ms) {
    if (!s_gamepad) return;
    Uint16 value = static_cast<Uint16>(intensity * 65535);
    SDL_RumbleGamepad(s_gamepad, value, value, duration_ms);
}

▼ main.cpp(使用例)

#include <iostream>
#include "game_controller.h"

int main() {
    if (!GameController::Initialize()) {
        std::cout << "Failed to initialize controller\n";
        return 1;
    }

    while (true) {
        GameController::Update();
        
        if (GameController::IsTrigger_ButtonA()) {
            std::cout << "Button A pressed!\n";
            GameController::StartVibration(0.5f, 500);
        }
        
        float stickX = GameController::GetLeftStickX();
        std::cout << "Left Stick X: " << stickX << "\n";
    }

    GameController::Finalize();
    return 0;
}

実行結果

実行すると、以下のようなデバッグモニタが表示されます:

Xbox・PlayStation・Switchのどのコントローラーでも同じコードで動作します。

【重要】私が実際にSDL導入で困った体験談

体験談1: SDL3.dllがないとエラーが出た

最初、ビルドは成功したのに実行すると「SDL3.dllが見つかりません」というエラーが出ました。原因は、SDL3.dllを実行ファイルと同じフォルダにコピーし忘れていたこと。Debugフォルダだけでなく、Releaseフォルダにもコピーする必要があります。

体験談2: XInputからSDLに移行して全機種対応できた

以前はXInputを使っていましたが、Steamで「PlayStation 5コントローラーで動かない!」というレビューが大量に届きました。急いでSDL3に移行したところ、Xbox・PS5・Switch Pro・Joy-Conすべてで動作するようになり、低評価レビューが激減しました。最初からSDLを使っておけばよかったと痛感しました。

SDL使用時のよくあるエラーと対処法

エラー1: SDL3/SDL.hが見つからない

原因: インクルードディレクトリの設定が間違っている
対処法: プロジェクトのプロパティで、$(SolutionDir)SDL3\includeが正しく設定されているか確認してください。

エラー2: SDL3.libがリンクできない

原因: ライブラリディレクトリが間違っている、またはx64とx86が合っていない
対処法: $(SolutionDir)SDL3\lib\x64(またはx86)が正しく設定されているか、プロジェクトのビルド構成と一致しているか確認してください。

エラー3: 実行時に「SDL3.dllが見つかりません」

原因: SDL3.dllが実行ファイルと同じフォルダにない
対処法: SDL3\lib\x64\SDL3.dllを、DebugReleaseの両方の出力フォルダにコピーしてください。

対応コントローラー一覧

メーカーコントローラー振動備考
MicrosoftXbox Series X/S/One/360完全対応
SonyDualShock 4タッチパッド非対応
SonyDualSense (PS5)アダプティブトリガー非対応
NintendoSwitch Pro Controller完全対応
NintendoJoy-Con (L/R)個別認識可
汎用DirectInput互換機種により異なる

注意点

  • ⚠️ SDL3.dllの配布: ゲームを配布する際は、必ずSDL3.dllを実行ファイルと一緒に配布してください
  • ⚠️ イベントループ: SDL3を使う場合、毎フレームSDL_PollEventを呼ぶ必要があります(GameController::Update()内で処理)
  • ⚠️ ボタン表記: Aボタンなど機種によって位置が異なるため、「決定」「キャンセル」など機能名で表記するのがおすすめです

まとめ

  • SDL3だけで全機種対応: Xbox・PlayStation・Nintendo Switchすべてに対応可能
  • クロスプラットフォーム: Windows・Mac・Linuxで同じコードが動く
  • 振動機能も完全対応: SDL_RumbleGamepadで統一的に制御
  • セットアップは簡単: .slnと同じディレクトリにSDL3を配置し、プロジェクト設定するだけ
  • GitHubで完全版公開: https://github.com/it-kashiros/controller_SDL

新規プロジェクトでゲームパッド対応を実装するなら、SDL3を使うのが最もシンプルで確実です。ぜひGitHubのコードを参考に、自分のゲームに組み込んでみてください!

関連記事