チュートリアル: DirectX ゲームへのタッチ コントロールの追加

ここでは、DirectX を使って基本的なタッチ コントロールをストア C++ ゲームに追加する方法について説明します。具体的には、平面に固定されたカメラを動かすタッチ ベースのコントロールを、指またはスタイラスでドラッグするとカメラの視点がシフトする Direct3D 環境に追加する方法を紹介します。

これらのコントロールは、プレイヤーが地図やプレイフィールドなどの 3D 環境でドラッグしてスクロールまたはパンを行うゲームに組み込むことができます。たとえば、戦略ゲームやパズル ゲームでは、これらのコントロールを使って、プレイヤーが左右にパンすることで画面より大きいゲーム環境を確認できるようにすることが可能です。

  ここで紹介するコードは、マウス ベースのパン コントロールにも利用できます。ポインター関連のイベントは、Windows ランタイム API で抽象化されるため、タッチまたはマウス ベースのポインター イベントを処理できます。

目標

  • DirectX ゲームで平面に固定されたカメラをパンする簡単なタッチ ドラッグ コントロールを作成する。

基本的なタッチ イベントのインフラストラクチャのセットアップ

まず、この例ではコントローラーの基本型として、CameraPanController を定義します。ここでは、コントローラーを抽象的な概念として定義します。つまり、ユーザーが実行できる一連の動作です。

CameraPanController クラスは、カメラ コントローラーの状態に関する情報を定期的に更新したコレクションであり、アプリが自身の更新ループからこの情報を取得できるようにします。


using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;

// Methods to get input from the UI pointers
ref class CameraPanController
{
}

次に、カメラ コントローラーの状態を定義するヘッダーと、カメラ コントローラーの操作を実装する基本的なメソッドとイベント ハンドラーを作ります。


ref class CameraPanController
{
private:
    // properties of the controller object
    float3 m_position;			    // the position of the camera

    // properties of the camera pan control
    bool m_panInUse;			    
    uint32 m_panPointerID;		    
    float2 m_panFirstDown;		    
    float2 m_panPointerPosition;   
    float3 m_panCommand;		    

public:

    // Methods to get input from the UI pointers
    void OnPointerPressed(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnPointerMoved(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnPointerReleased(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    // set up the Controls supported by this controller
    void Initialize( _In_ Windows::UI::Core::CoreWindow^ window );

    // accessor to set the position of the ontroller
    void SetPosition( _In_ float3 pos );

	   // accessor to set fixed "look point" of the controller
	   float3 get_FixedLookPoint();

    // returns the position of the controller object
    float3 get_Position();


    void Update( Windows::UI::Core::CoreWindow ^window );

};  // class CameraPanController

プライベート フィールドには、カメラ コントローラーの現在の状態が含まれています。ここでその内容を確認してみましょう。

  • m_position は、シーン空間内のカメラの位置です。この例では、z 座標値は 0 に固定されています。float2 を使ってこの値を表すこともできますが、このサンプルの目的と今後の拡張性を考慮して、ここでは float3 を使います。この値は、get_Position プロパティを通じてアプリ自体に渡し、それに従ってアプリがビューポートを更新できるようにします。
  • m_panInUse は、パン操作がアクティブかどうかを示すブール値です。より具体的には、プレイヤーが画面をタッチしてカメラを動かしているかどうかを示します。
  • m_panPointerID は、ポインターの一意の ID です。これはこのサンプルでは使いませんが、コントローラーの状態クラスと特定のポインターを関連付けることをお勧めします。
  • m_panFirstDown は、カメラのパン操作中にプレイヤーが最初に画面をタッチまたはマウスをクリックした画面上の点です。この値は、画面がタッチされているときに、ビューが不安定にならないようデッド ゾーンを設定するために後で使います。またはマウスが少し揺れているときです。
  • m_panPointerPosition は、プレイヤーがポインターを現在動かしたばかりの画面上の点です。これは、m_panFirstDown と比較して確認することで、プレイヤーが移動したい方向を判断するために使います。
  • m_panCommand は、カメラ コントローラーに対して計算された最終的なコマンドであり、up、down、left、または right です。x-y 平面に固定されたカメラを操作しているため、これは、float2 にすることも可能です。

次の 3 つのイベント ハンドラーを使って、カメラ コントローラーの状態情報を更新します。

  • OnPointerPressed は、プレイヤーが指でタッチ画面を押し、その押された座標にポインターが動いたときに、アプリが呼び出すイベント ハンドラーです。
  • OnPointerMoved は、プレイヤーが指でタッチ画面をスワイプしたときに、アプリが呼び出すイベント ハンドラーです。これは、ドラッグ パスの新しい座標で更新されます。
  • OnPointerReleased は、プレイヤーが指をタッチ画面から離したときに、アプリが呼び出すイベント ハンドラーです。

最後に、次のメソッドとプロパティを使って、カメラ コントローラーの状態情報の初期化、アクセス、更新を行います。

  • Initialize は、アプリがコントロールを初期化して、表示ウィンドウを定義する CoreWindow オブジェクトにそれらのコントロールを適用するときに呼び出すイベント ハンドラーです。
  • SetPosition は、アプリがシーン空間内のコントロールの (x、y、z) 座標を設定するときに呼び出すメソッドです。z 座標はこのチュートリアル全体で 0 であることに注意してください。
  • get_Position は、アプリがシーン空間内のカメラの現在の位置を取得するときにアクセスするプロパティです。このプロパティは、カメラの現在の位置をアプリに伝える手段として使います。
  • get_FixedLookPoint は、アプリが現在コントローラーのカメラが向いている点を取得するときにアクセスするプロパティです。この例では、x-y 平面に垂直にロックされています。
  • Update は、コントローラーの状態を読み取り、カメラの位置を更新するメソッドです。このメソッドをアプリのメイン ループから継続的に呼び出して、カメラ コントローラーのデータとシーン空間内のカメラの位置を更新します。

これで、タッチ コントロールの実装に必要なコンポーネントがすべて揃いました。タッチ ポインターまたはマウス ポインターのイベントがいつどこで発生し、その操作が何かを検出できます。また、カメラの位置と向きをシーン空間と相対的に設定し、変化を追跡できます。さらに、カメラの新しい位置を呼び出し元アプリに伝えることができます。

次は、これらのコンポーネントどうしを接続してみましょう。

基本的なタッチ イベントの作成

Windows ランタイムのイベント ディスパッチャーは、アプリで処理するイベントを 3 つ提供します。

これらのイベントは、CoreWindow 型に実装されています。ここでは、操作する CoreWindow オブジェクトが既にあると想定しています。詳しくは、「DirectX Windows ストア アプリでビューを表示するための設定方法」をご覧ください。

これらのイベントは Windows ストア アプリの実行中に起動するため、ハンドラーはプライベート フィールドに定義されているカメラ コントローラーの状態情報を更新します。

まず、タッチ ポインターのイベント ハンドラーを設定します。最初のイベント ハンドラーである OnPointerPressed では、ユーザーが画面をタッチまたはマウスをクリックすると、表示を管理する CoreWindow からポインターの x-y 座標を取得します。

OnPointerPressed


void CameraPanController::OnPointerPressed(
                                           _In_ CoreWindow^ sender,
                                           _In_ PointerEventArgs^ args)
{
    // get the current pointer position
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    auto device = args->CurrentPoint->PointerDevice;
    auto deviceType = device->PointerDeviceType;
    

	   if ( !m_panInUse )	// if no pointer is in this control yet
    {
       m_panFirstDown = position;					// save location of initial contact
       m_panPointerPosition = position;
       m_panPointerID = pointerID;				// store the id of pointer using this control
       m_panInUse = TRUE;
    }
    
}


このハンドラーを使って、現在の CameraPanController インスタンスに、m_panInUse を TRUE に設定してカメラ コントローラーをアクティブとして扱う必要があることを伝えます。この方法により、アプリは Update を呼び出すときに、現在の位置データを使ってビューポートを更新します。

以上で、ユーザーが画面をタッチまたは表示ウィンドウをクリックしたときのカメラの動きを示す基本の値が設定されたので、次は、ユーザーが画面を押してドラッグまたはボタンを押してマウスを動かしたときに何をするかを決める必要があります。

OnPointerMoved イベント ハンドラーは、ポインターが動くたびに、プレイヤーがポインターを画面上でドラッグするティックごとに起動します。アプリにポインターの現在の位置を知らせ続ける必要があるため、次のように指定します。

OnPointerMoved


void CameraPanController::OnPointerMoved(
                                        _In_ CoreWindow ^sender,
                                        _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    m_panPointerPosition = position;
}

最後に、プレイヤーが画面から手を離したときに、カメラのパン動作を非アクティブにする必要があります。m_panInUse を FALSE に設定してカメラのパン移動をオフにし、ポインター ID を 0 に設定するには、PointerReleased の起動時に呼び出される OnPointerReleased を使います。

OnPointerReleased


void CameraPanController::OnPointerReleased(
                                             _In_ CoreWindow ^sender,
                                             _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    m_panInUse = FALSE;
    m_panPointerID = 0;
}

タッチ コントロールとコントローラーの状態の初期化

次は、イベントをフックして、カメラ コントローラーの状態の基本的なフィールドをすべて初期化しましょう。

Initialize


void CameraPanController::Initialize( _In_ CoreWindow^ window )
{

    // Start recieving touch/mouse events
    window->PointerPressed += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerPressed);

    window->PointerMoved += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerMoved);

    window->PointerReleased += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerReleased);


    // Initialize state of the controller
    m_panInUse = FALSE;				
    m_panPointerID = 0;

    //	Initialize this as it is reset every frame
    m_panCommand = float3( 0.0f, 0.0f, 0.0f );

}

Initialize は、アプリの CoreWindow インスタンスへの参照をパラメーターとして使い、先ほど作成したイベント ハンドラーをその CoreWindow の適切なイベントに登録します。

カメラ コントローラーの位置の取得と設定

シーン空間内のカメラ コントローラーの位置の取得と設定を行うメソッドをいくつか定義してみましょう。


void CameraPanController::SetPosition( _In_ float3 pos )
{
    m_position = pos;
}

// Returns the position of the controller object
float3 CameraPanController::get_Position()
{
    return m_position;
}

float3 CameraPanController::get_FixedLookPoint()
{
    // For this sample, we don't need to use the trig functions because our
    // look point is fixed. 
    return m_position + float3( 0, 0, 1 );
}

SetPosition は、カメラ コントローラーの位置を特定の点に設定する必要がある場合に、アプリから呼び出すことができるパブリック メソッドです。

get_Position は、最も重要なパブリック プロパティです。アプリはこのプロパティを使って、シーン空間内のカメラ コントローラーの現在の位置を取得し、その位置に応じてビューポートを更新できます。

get_FixedLookPoint は、この例では、x-y 平面に垂直な視点を取得するパブリック プロパティです。固定カメラに対して斜めの角度を作る場合は、このメソッドを変更して、x、y、z 座標値の計算時に三角関数 sin と cos を使うことができます。

カメラ コントローラーの状態情報の更新

次は、m_panPointerPosition で追跡したポインターの座標情報を、3D シーン空間における新しい座標情報に変換する計算を実行します。Windows ストア アプリは通常、アプリのメイン ループが更新されるたびに、このメソッドを呼び出します。ビュー マトリックスをビューポートへのプロジェクションの前に更新するためにアプリに渡す新しい視点位置情報は、ここで計算します。




void CameraPanController::Update( CoreWindow ^window )
{
    if ( m_panInUse )
    {
        float2 pointerDelta = m_panPointerPosition - m_panFirstDown;

        if ( pointerDelta.x > 16.0f )		// leave 32 pixel-wide dead spot for being still
            m_panCommand.x += 1.0f;
        else
            if ( pointerDelta.x < -16.0f )
                m_panCommand.x += -1.0f;

        if ( pointerDelta.y > 16.0f )		
            m_panCommand.y += 1.0f;
        else
            if (pointerDelta.y < -16.0f )
                m_panCommand.y += -1.0f;
    }

	   float3 command = m_panCommand;
   
    // our velocity is based on the command
    float3 Velocity;
    Velocity.x =  command.x;
    Velocity.y =  command.y;
    Velocity.z =  0.0f;

    // integrate
    m_position = m_position + Velocity;

    // Clear the movement input accumulator for use during next frame
    m_panCommand = float3( 0.0f, 0.0f, 0.0f );

}

タッチまたはマウスの揺れでカメラのパンが不適切に動かないように、ポインターの周りに直径 32 ピクセルのデッド ゾーンを設定します。また、速度値もあります。この例では、デッド ゾーンを超えるポインターのピクセル トラバーサルに対して 1:1 です。この動作を調整し、移動速度を低下または上昇させることができます。

カメラの新しい位置によるビュー マトリックスの更新

これで、カメラのフォーカスが合っているシーン空間の座標の取得ができます。この座標は、アプリに指定した時間ごとに更新されます (たとえばアプリのメイン ループでは 60 秒ごと)。 次の疑似コードは、実装できる呼び出し動作を示しています。


 myCameraPanController->Update( m_window );	

 // update the view matrix based on the camera position
 myCamera->MyMethodToComputeViewMatrix(
        myController->get_Position(),		// the position in the 3D scene space
        myController->get_FixedLookPoint(),		// the point in the space we are looking at
        float3( 0, 1, 0 )					// the axis that is "up" in our space
        );	

これで、一連の簡単なカメラ パンのタッチ コントロールが DirectX と C++ を使った Windows ストア アプリに実装されました。

 

 

表示:
© 2015 Microsoft