次の方法で共有


XInput から GameInput への移植

XInput から GameInput への移植は、従来のどの API よりも簡単です。 これは、GameInput が XInput のシンプルで使いやすいプログラミング モデルの影響を強く受けており、これにより、多くの XInput API は GameInput の同等の関数に 1:1 で対応しているためです。

主要な相違点

以下のセクションでは、XInput と GameInput の主な相違点について説明します。

C と C++

XInput API はフラット C 関数の集合です。 一方、GameInput は C ++ であり、(グラフィックスやオーディオの API のように) インターフェイスを使用します。 実際には、これによって GameInput API を使用するコードが複雑になったりパフォーマンスが影響を受けたりすることはなく、GameInput のしくみをよく理解すれば、いくつかのメリットが得られることがわかるはずです。

これらのインターフェイスは COM のように見えるかもしれませんが、そうではないことを理解することが重要です。 これらのインターフェイスを使用するには、参照カウントの基本的な知識のみが必要です。 詳細については、「 GameInput fundamentals (GameInput の基礎)」トピックの「Interfaces (インターフェイス)」セクションを参照してください。

入力の取得

XInput では、ほとんどのゲームは、接続されたデバイスで見つかるまでユーザー インデックスをループ処理し、そのデバイスから状態を読み取ります。 多くの場合、ゲームは、次回にループする必要がないようにユーザー インデックスを記憶します。 たとえば、次のコードはユーザーにコントローラーの "A ボタンを押す" よう求めるゲームの典型的な例です。

// This function looks for a gamepad that currently has the "A" button pressed.
void FindActiveGamepad()
{
    for (DWORD index = 0; index < XUSER_MAX_COUNT; index++)
    {
        XINPUT_STATE state;
        if (XInputGetState(index, &state) == ERROR_SUCCESS)
        {
            if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A)
            {
                // Found the user's gamepad at this index.
            }
        }
    }
}

GameInput では、最初にデバイスを指定せずに入力を取得し、必要に応じて、どのデバイスから入力が発生したのかというクエリを実行できます。 コードは似ていますが、明示的なデバイス列挙が不要になるため、アルゴリズムが単純になります。

// This function looks for a gamepad that currently has the "A" button pressed.
void FindActiveGamepad(IGameInput * gameInput)
{
    // This checks for input from all gamepads simultaneously.
    IGameInputReading * reading;
    if (SUCCEEDED(gameInput->GetCurrentReading(GameInputKindGamepad, nullptr, &reading)))
    {
        GameInputGamepadState state;
        reading->GetGamepadState(&state);

        if (state.buttons & GameInputGamepadA)
        {
            // Found the user's gamepad.  At this point we can
            // get the device that generated this input, and then
            // pass that into future calls to the GetCurrentReading
            // method to receive input only from that gamepad.
        }

        reading->Release():
    }
}

コードは XInput ほど単純ではありませんが、非常によく似ています。 GameInput API をよく理解することで、このモデルでは、XInput にはない入力を処理するための強力なオプションが使用できることがわかります。

XInput では、トリガーからのアナログの値が BYTE 型として、サムスティックからのアナログの値が SHORT 型として返されます。 GameInput API では、これらのアナログの値は、0 から 1 (トリガー) あるいは -1 から 1 (サムスティック) の float 値として返されます。

ランブル (振動) フィードバック

XInput では、ゲームは XInputSetState を呼び出して、ランブル (振動) コマンドのデバイスへの送信のみを行います。 GameInput では、ゲームはデバイスの IGameInputDevice インスタンスを取得してから、その SetRumbleState メソッドを呼び出す必要があります。 これらの 2 つのメソッドは、使用法が類似しています。 これはデバイス識別子だけでなく、デバイス インターフェイスで関数を呼び出す場合の例です。

アプリケーションのフォーカス

本体では、GameInput は、アプリケーションにフォーカスがあるときにのみ、入力をアプリケーションに提供します。 それ以外の場合、返される状態には、ユーザーがデバイスにまったく触れていないかのようにニュートラルまたは "休止" の値が含まれます。 これにより、フォーカスの変更を処理する追加の入力コード (XInputEnable の呼び出しなど) が不要になります。

PC では、既定ですべてのプロセスに入力が行われます。 今後、この動作は SetFocusPolicy メソッドを使用して変更できるようになります。

XInputOnGameInput ラッパー

Microsoft Game Development Kit (GDK) には、GameInput の上に XInput API の実装を含むヘッダー ファイル「XInputOnGameInput.h」が付属しています。 特にキーボードやマウスなどの入力デバイスが必要な場合は、GameInput に直接移植することをお勧めします。 しかし、XInputOnGameInput ラッパーを使用すると、既存の XInput コードに変更を加えずに初期の移植作業をブートストラップできます。

XInputOnGameInput ラッパーを使用するには、単に次のコードを

#include <XInput.h>

次のコードに置き換えます。

#include <XInputOnGameInput.h>
using namespace XInputOnGameInput;

その後で、コードを再コンパイルします。

XInput ラッパー コードの実装は完全にこのヘッダー ファイル内にあるので、GameInput API を使用したり必要に応じて変更したりする例として調べることもできます。

XInput と XInputOnGameInput の違い

一般的に、XInputOnGameInput ラッパーは従来の XInput API と直接置き換えて使用することができます。 ただし、わずかな違いがいくつかあります。

  • 簡略化のために、ラッパーにはゲームパッド デバイスのサポートのみがコード化されています。 レーシング ホイールやアーケード スティックなどの他のデバイスをサポートする必要がある場合は、GameInput を直接使用するか、XInputOnGameInput コードにそれらのデバイスのサポートを追加する必要があります。

  • ラッパーは、ゲームがフォーカスされている場合にのみゲーム パッド入力を返します。 ゲームがフォーカスされていない場合は、返されるゲーム パッドの状態がニュートラルまたは "rest" 値に設定され、ユーザーがゲームパッドに触れてないのと同じような状態になります。 これは、XInputEnable への呼び出しに関係なく (呼び出しがない場合でも) 行われます。

  • XUSER_MAX_COUNT の値が 4 から 8 に増加しました。 これは通常、ほとんどの従来の XInput コードにとって透過的です。 ただし、コード内で XInputGetKeystroke 関数の使用箇所を注意深く調べて、XINPUT_KEYSTROKE 構造体の UserIndex メンバーで返される値の最大値を 4 と想定してハードコードされた箇所がないことを必ず確認してください。 これを行わないと、バッファー オーバーランが発生する可能性があります。

  • 運用コードでも引き続き XInput ラッパーを使用する場合にのみ必要となる、新しい関数がいくつか追加されました (以下を参照)。

運用コードでの XInputOnGameInput の使用

XInputOnGameInput ラッパーは、高性能でロックフリーとして作成されており、GameInput API のパフォーマンスの最適化をすべて継承しています。そのため、運用コードでの使用に適しています。 一般的な HID ゲームパッドなど、GameInput の幅広いデバイス サポートも継承します。また、次の新規関数を API に追加します。

  • XInputSetStateExXInputSetState に似ていますが、トリガー モーターのサポートを追加します。

  • XInputGetStateWithTokenXInputGetState に似ていますが、呼び出し元は D3DX フレーム パイプライン トークンを提供して、PIX で後で解析するために特定の入力読み取り値をグラフィックス フレームに関連付けることができます。

    注意

    5 月のプレビュー リリース時点では、基になる GameInput コードが完全に実装されていないため、XInputGetStateWithToken は現在 XInputGetState と同じように動作します。

  • XInputGetDeviceId は、指定したユーザー インデックスでデバイスの APP_LOCAL_DEVICE_ID を返します。 この ID を IGameInputFindDeviceFromId メソッドに渡すと、そのユーザー インデックスに対応する IGameInputDevice が返されます。 これを使用して、XInput ラッパーを介して公開されない GameInput API の追加機能にアクセスすることができます。

ラッパー コードの最適化

既定では、XInputOnGameInput ラッパーは従来の XInput API とのドロップイン互換性を持つように構成されます。 100% の互換性のある動作を必要としないゲームでは、次のいずれかのプリプロセッサのマクロを定義することにより、ラッパーの動作とパフォーマンスを微調整できます。

XINPUT_ON_GAMEINPUT_EXPLICIT_INITIALIZATION

既定では、XInput ラッパーは、いずれかのラッパー関数が最初に呼び出されたときに基になる GameInput API を自動的に遅延初期化します。 これにより既存の XInput コードとのドロップイン互換性が確保されますが、いくつかの小さな欠点があります。

  1. 最初の XInput ラッパー関数の呼び出しの実行時間が、通常よりも長くなります。

  2. すべての XInput ラッパー関数は、呼び出されるたびに、遅延初期化が実行されたかどうかを確認するためのチェックを実行する必要があります。 これはグローバル変数の単純なテストであるため、分岐予測器によってコストが改善されるはずですが、それでも余分なオーバーヘッドが発生します。

  3. エラーが発生することはありませんが、基になる GameInput API の遅延初期化が成功したかどうかを判断することはできません。

  4. 基になる IGameInput インスタンスは、(モジュールのアンロードまたはプロセスの終了により) XInput ラッパーのグローバル変数がクリーンアップされるまで解放されません。

ゲームは、XINPUT_ON_GAMEINPUT_EXPLICIT_INITIALIZATION マクロを定義することにより、ラッパーの初期化とシャットダウンを手動で制御することができます。 これにより 2 つの新しい関数 XInputOnGameInputInitializeXInputOnGameInputUninitialize が追加され、これらの関数を呼び出して初期化とシャットダウンの発生するタイミングを正確に制御できます。

XINPUT_ON_GAMEINPUT_NO_XINPUTENABLE

XInputEnable 関数の実装に必要なコードは、XInputGetStateXInputGetStateWithToken, XInputSetStateXInputSetStateExXInputGetKeystroke 関数のすべての呼び出しに余分なオーバーヘッドを追加します。 コードが XInputEnable を呼び出さない場合や、コードからそれを簡単に除去できる場合は、XINPUT_ON_GAMEINPUT_NO_XINPUTENABLE マクロを定義すると、XInputEnable のサポートとそれに関連して発生するオーバーヘッドを除去することができます。 基になる GameInput コードはフォーカスが変化したときに XInputEnable の機能を自動的に実行するため、ほとんどのゲームでは、可能な場合はこのマクロを定義する必要があります。

XINPUT_ON_GAMEINPUT_NO_XINPUTGETKEYSTROKE

XInputGetKeystroke 関数の実装に必要なコードは、ラッパーの実装にいくつかの余分な関数と変数を追加します。 これによって他の XInput API 関数にオーバーヘッドが追加されることはありませんが、コードが XInputGetKeystroke を呼び出さない場合は、XINPUT_ON_GAMEINPUT_NO_XINPUTGETKEYSTROKE マクロを定義して XInput ラッパーのコード/サイズを少し減らすことができます。

関連項目

GameInput の概要

GameInput API リファレンス

Microsoft Game Development Kit