ゲームのムーブルック コントロール

従来のマウスおよびキーボードのムーブルック コントロール (mouselook コントロールとも呼ばれます) を DirectX ゲームに追加する方法について説明します。

また、タッチ デバイスの移動外観のサポートについて説明します。移動コントローラーは方向入力のように動作する画面の左下セクションとして定義され、画面の残りの部分に対して定義されたルック コントローラーは、プレイヤーがその領域で最後にタッチした場所を中心にしてカメラを中心にしています。

これが慣れないコントロールの概念である場合は、キーボード (またはタッチベースの方向入力ボックス) によってこの 3D 空間内の足が制御され、脚が前方または後方に移動することしかできないか、左右にストレーフィングできるかのように動作します。 マウス (またはタッチ ポインター) によって頭が制御されます。 頭を使用して方向 (左または右、上または下、またはその平面内のどこか) を確認します。 ビューにターゲットがある場合は、マウスを使用してカメラ ビューをそのターゲットの中央に配置し、そのターゲットに向かって移動するには前方キーを押すか、戻って移動します。 ターゲットを円で囲むには、カメラ ビューをターゲットの中央に維持し、左右に同時に移動します。 これが3D環境をナビゲートするための非常に効果的な制御方法であることがわかります。

これらのコントロールは、W、A、S、および D キーを x-z 平面固定カメラの移動に使用し、マウスを使用して x 軸と y 軸の周りのカメラの回転を制御する、ゲームの WASD コントロールとして一般的に知られています。

目標

  • マウスとキーボード、およびタッチ スクリーンの両方の基本的なムーブルック コントロールを DirectX ゲームに追加します。
  • 3D 環境をナビゲートするために使用する一人称カメラを実装します。

タッチ コントロールの実装に関する注意事項

タッチ コントロールの場合、2 つのコントローラーを実装します。ムーブ コントローラーは、カメラのルック ポイントに対する x-z 平面内の動きを処理します。カメラのルックポイントを目指すルックコントローラ。 移動コントローラーはキーボードの WASD ボタンにマップされ、ルック コントローラーはマウスにマップされます。 ただし、タッチ コントロールの場合は、方向入力として機能する画面の領域、または仮想 WASD ボタンを定義する必要があります。画面の残りの部分はルック コントロールの入力スペースとして機能します。

画面は次のようになります。

ムーブルック コントローラーのレイアウト

画面の左下にあるタッチ ポインター (マウスではない) を移動すると、上に向かって動くと、カメラが前方に移動します。 下方向に移動すると、カメラは後方に移動します。 移動コントローラーのポインター空間内での左右の移動も同じです。 その空間の外側で、見た目のコントローラーになります。カメラをタッチするか、カメラを向きたい場所にドラッグするだけです。

基本的な入力イベント インフラストラクチャを設定する

まず、マウスとキーボードからの入力イベントを処理するために使用するコントロール クラスを作成し、その入力に基づいてカメラのパースペクティブを更新する必要があります。 移動外観コントロールを実装しているため、これをMoveLookController 呼び出

using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;
#include <DirectXMath.h>

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

次に、ムーブルック コントローラーとその一人称カメラの状態を定義するヘッダーに加えて、コントロールを実装し、カメラの状態を更新する基本的なメソッドとイベント ハンドラーを作成しましょう。

#define ROTATION_GAIN 0.004f    // Sensitivity adjustment for the look controller
#define MOVEMENT_GAIN 0.1f      // Sensitivity adjustment for the move controller

ref class MoveLookController
{
private:
    // Properties of the controller object
    DirectX::XMFLOAT3 m_position;               // The position of the controller
    float m_pitch, m_yaw;           // Orientation euler angles in radians

    // Properties of the Move control
    bool m_moveInUse;               // Specifies whether the move control is in use
    uint32 m_movePointerID;         // Id of the pointer in this control
    DirectX::XMFLOAT2 m_moveFirstDown;          // Point where initial contact occurred
    DirectX::XMFLOAT2 m_movePointerPosition;   // Point where the move pointer is currently located
    DirectX::XMFLOAT3 m_moveCommand;            // The net command from the move control

    // Properties of the Look control
    bool m_lookInUse;               // Specifies whether the look control is in use
    uint32 m_lookPointerID;         // Id of the pointer in this control
    DirectX::XMFLOAT2 m_lookLastPoint;          // Last point (from last frame)
    DirectX::XMFLOAT2 m_lookLastDelta;          // For smoothing

    bool m_forward, m_back;         // States for movement
    bool m_left, m_right;
    bool m_up, m_down;


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
        );

    void OnKeyDown(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::KeyEventArgs^ args
        );

    void OnKeyUp(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::KeyEventArgs^ args
        );

    // Set up the Controls that this controller supports
    void Initialize( _In_ Windows::UI::Core::CoreWindow^ window );

    void Update( Windows::UI::Core::CoreWindow ^window );
    
internal:
    // Accessor to set position of controller
    void SetPosition( _In_ DirectX::XMFLOAT3 pos );

    // Accessor to set position of controller
    void SetOrientation( _In_ float pitch, _In_ float yaw );

    // Returns the position of the controller object
    DirectX::XMFLOAT3 get_Position();

    // Returns the point  which the controller is facing
    DirectX::XMFLOAT3 get_LookPoint();


};  // class MoveLookController

このコードには、プライベート フィールドの 4 つのグループが含まれています。 それぞれの目的を確認しましょう。

まず、カメラ ビューに関する更新された情報を保持するいくつかの便利なフィールドを定義します。

  • m_position は、3D シーン内のカメラ (とビュー平面) の位置であり、シーンの座標を使います。
  • m_pitch は、カメラのピッチ (ビュー平面の x 軸を中心とする上下の回転) であり、単位はラジアンです。
  • m_yaw は、カメラのヨー (ビュー平面の y 軸を中心とする左右の回転) であり、単位はラジアンです。

次に、コントローラーの状態と位置に関する情報を格納するために使用するフィールドを定義しましょう。 まず、タッチ ベースの移動コントローラーに必要なフィールドを定義します。 (移動コントローラーのキーボード実装に特別な必要はありません。特定のハンドラーを使用してキーボード イベントを読み取るだけです)。

  • m_moveInUse は、ムーブ コントローラーが使用中かどうかを示します。
  • m_movePointerID は、現在のムーブ ポインターの一意の ID です。 これを使用して、ポインター ID 値を確認するときに、ルック ポインターと移動ポインターを区別します。
  • m_moveFirstDown は、プレイヤーがムーブ コントローラーのポインター領域で最初にタッチした画面上の点です。 この値を後で使用して、小さな動きがビューをジッターしないようにデッド ゾーンを設定します。
  • m_movePointerPosition は、プレイヤーがポインターを今動かした先の画面上の点です。 これは、m_moveFirstDown と比較して確認することで、プレイヤーが移動したい方向を判断するために使います。
  • m_moveCommand は、ムーブ コントローラーに対して計算された最終的なコマンドであり、up (前進)、down (後退)、left (左)、または right (右) です。

ここでは、マウスとタッチの両方の実装で、ルック コントローラーに使用するフィールドを定義します。

  • m_lookInUse は、ルック コントロールが使用中かどうかを示します。
  • m_lookPointerID は、現在のルック ポインターの一意の ID です。 これを使用して、ポインター ID 値を確認するときに、ルック ポインターと移動ポインターを区別します。
  • m_lookLastPoint は、シーンの座標内の、前のフレーム内でキャプチャされた最後の点です。
  • m_lookLastDelta は、現在の m_positionm_lookLastPoint との違いを計算した値です。

最後に、6 度の移動に対して 6 つのブール値を定義します。これは、各方向移動アクションの現在の状態を示すために使用します (オンまたはオフ)。

  • m_forwardm_backm_leftm_rightm_upm_down

6 つのイベント ハンドラーを使用して、コントローラーの状態を更新するために使用する入力データをキャプチャします。

  • OnPointerPressed。 プレイヤーがマウスの左ボタンを押してゲーム画面にポインターを置くか、画面にタッチしました。
  • OnPointerMoved。 プレイヤーは、ゲーム画面でポインターを使用してマウスを移動するか、画面上のタッチ ポインターをドラッグしました。
  • OnPointerReleased。 プレイヤーがマウスの左ボタンをゲーム画面のポインターと共に離すか、画面に触れるのを停止しました。
  • OnKeyDown。 プレーヤーがキーを押しました。
  • OnKeyUp。 プレーヤーがキーを解放しました。

最後に、これらのメソッドとプロパティを使用して、コントローラーの状態情報を初期化、アクセス、および更新します。

  • Initialize。 このアプリは、このイベント ハンドラーを呼び出してコントロールを初期化し、表示ウィンドウを記述する CoreWindow オブジェクトにアタッチします。
  • SetPosition。 このアプリでは、このメソッドを呼び出して、シーン空間内のコントロールの (x、y、z) 座標を設定します。
  • SetOrientation。 このアプリはこのメソッドを呼び出して、カメラのピッチとヨーを設定します。
  • get_Position。 アプリはこのプロパティにアクセスして、シーン空間内のカメラの現在位置を取得します。 このプロパティは、現在のカメラ位置をアプリに通信する方法として使用します。
  • get_LookPoint。 このアプリは、このプロパティにアクセスして、コントローラー カメラが向いている現在のポイントを取得します。
  • 更新。 移動コントローラーとルック コントローラーの状態を読み取り、カメラの位置を更新します。 アプリのメイン ループからこのメソッドを継続的に呼び出して、カメラ コントローラーデータとシーン空間内のカメラ位置を更新します。

ここでは、ムーブルック コントロールを実装するために必要なすべてのコンポーネントを用意しました。 それでは、これらの部分を結び付けましょう。

基本的な入力イベントを作成する

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

これらのイベントは、CoreWindow 型に実装されています。 ここでは、操作する CoreWindow オブジェクトが既にあると想定しています。 取得方法がわからない場合は、「 DirectX ビューを表示するように ユニバーサル Windows プラットフォーム (UWP) C++ アプリを設定する方法を参照してください。

アプリの実行中にこれらのイベントが発生すると、ハンドラーはプライベート フィールドで定義されているコントローラーの状態情報を更新します。

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

OnPointerPressed

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

    auto device = args->CurrentPoint->PointerDevice;
    auto deviceType = device->PointerDeviceType;
    if ( deviceType == PointerDeviceType::Mouse )
    {
        // Action, Jump, or Fire
    }

    // Check  if this pointer is in the move control.
    // Change the values  to percentages of the preferred screen resolution.
    // You can set the x value to <preferred resolution> * <percentage of width>
    // for example, ( position.x < (screenResolution.x * 0.15) ).

    if (( position.x < 300 && position.y > 380 ) && ( deviceType != PointerDeviceType::Mouse ))
    {
        if ( !m_moveInUse ) // if no pointer is in this control yet
        {
            // Process a DPad touch down event.
            m_moveFirstDown = position;                 // Save the location of the initial contact.
            m_movePointerPosition = position;
            m_movePointerID = pointerID;                // Store the id of the pointer using this control.
            m_moveInUse = TRUE;
        }
    }
    else // This pointer must be in the look control.
    {
        if ( !m_lookInUse ) // If no pointer is in this control yet...
        {
            m_lookLastPoint = position;                         // save the point for later move
            m_lookPointerID = args->CurrentPoint->PointerId;  // store the id of pointer using this control
            m_lookLastDelta.x = m_lookLastDelta.y = 0;          // these are for smoothing
            m_lookInUse = TRUE;
        }
    }
}

このイベント ハンドラーは、ポインターがマウスではない (マウスとタッチの両方をサポートするこのサンプルの目的で) かどうか、およびポインターが移動コントローラー領域にあるかどうかを確認します。 両方の条件が true の場合は、m_moveInUse が false かどうかをテストして、ポインターが押されたばかりかどうか、具体的には、このクリックが前のムーブ入力またはルック入力に無関係かどうかを確認します。 無関係な場合、ハンドラーはムーブ コントローラー領域で押し操作が発生した点をキャプチャして m_moveInUse を true に設定し、このハンドラーが再び呼び出されたときにムーブ コントローラーの入力操作の開始位置が上書きされないようにします。 また、移動コントローラー ポインター ID を現在のポインターの ID に更新します。

ポインターがマウスの場合、またはタッチ ポインターが移動コントローラー領域にない場合は、ルック コントローラー領域にある必要があります。 このハンドラーは、ユーザーがマウスのボタンを押した、またはタッチして押した現在の場所に m_lookLastPoint を設定し、差分をリセットして、ルック コントローラーのポインター ID を現在のポインターの ID に更新します。 また、ルック コントローラーの状態をアクティブに設定します。

OnPointerMoved

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

    // Decide which control this pointer is operating.
    if (pointerID == m_movePointerID)           // This is the move pointer.
    {
        // Move control
        m_movePointerPosition = position;       // Save the current position.

    }
    else if (pointerID == m_lookPointerID)      // This is the look pointer.
    {
        // Look control

        DirectX::XMFLOAT2 pointerDelta;
        pointerDelta.x = position.x - m_lookLastPoint.x;        // How far did pointer move
        pointerDelta.y = position.y - m_lookLastPoint.y;

        DirectX::XMFLOAT2 rotationDelta;
        rotationDelta.x = pointerDelta.x * ROTATION_GAIN;   // Scale for control sensitivity.
        rotationDelta.y = pointerDelta.y * ROTATION_GAIN;

        m_lookLastPoint = position;                     // Save for the next time through.

                                                        // Update our orientation based on the command.
        m_pitch -= rotationDelta.y;                     // Mouse y increases down, but pitch increases up.
        m_yaw -= rotationDelta.x;                       // Yaw is defined as CCW around the y-axis.

                                                        // Limit the pitch to straight up or straight down.
        m_pitch = (float)__max(-DirectX::XM_PI / 2.0f, m_pitch);
        m_pitch = (float)__min(+DirectX::XM_PI / 2.0f, m_pitch);
    }
}

OnPointerMoved イベント ハンドラーは、ポインターが移動するたびに起動します (この場合、タッチ スクリーン ポインターがドラッグされている場合、または左ボタンが押されている間にマウス ポインターが移動されている場合)。 ポインター ID がムーブ コントローラー ポインターの ID と同じ場合は、移動ポインターになります。それ以外の場合は、アクティブなポインターであるルック コントローラーであるかどうかを確認します。

移動コントローラーの場合は、ポインターの位置を更新するだけです。 PointerMoved イベントが発生し続ける限り更新を続けます。これは、最終的な位置と、OnPointerPressed イベント ハンドラーでキャプチャした最初の位置を比較するためです。

ルック コントローラーの場合は、もう少し複雑になります。 新しいルック ポイントを計算し、カメラを中央に配置する必要があるため、最後のルック ポイントと現在の画面位置の間の差分を計算し、スケール ファクターと乗算します。これを調整して、画面の動きの距離に対する外観の動きを小さくまたは大きくすることができます。 この値を使用して、ピッチとヨーを計算します。

最後に、プレイヤーがマウスの移動や画面へのタッチを停止したときに、移動またはルック コントローラーの動作を非アクティブ化する必要があります。 m_moveInUse または m_lookInUse を FALSE に設定してカメラのパン移動をオフにし、ポインター ID をゼロにするには、PointerReleased の起動時に呼び出す OnPointerReleased を使います。

OnPointerReleased

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


    if ( pointerID == m_movePointerID )    // This was the move pointer.
    {
        m_moveInUse = FALSE;
        m_movePointerID = 0;
    }
    else if (pointerID == m_lookPointerID ) // This was the look pointer.
    {
        m_lookInUse = FALSE;
        m_lookPointerID = 0;
    }
}

これまでは、すべてのタッチ スクリーン イベントを処理しました。 次に、キーボード ベースの移動コントローラーのキー入力イベントを処理してみましょう。

OnKeyDown

void MoveLookController::OnKeyDown(
                                   __in CoreWindow^ sender,
                                   __in KeyEventArgs^ args )
{
    Windows::System::VirtualKey Key;
    Key = args->VirtualKey;

    // Figure out the command from the keyboard.
    if ( Key == VirtualKey::W )     // Forward
        m_forward = true;
    if ( Key == VirtualKey::S )     // Back
        m_back = true;
    if ( Key == VirtualKey::A )     // Left
        m_left = true;
    if ( Key == VirtualKey::D )     // Right
        m_right = true;
}

これらのキーのいずれかが押されている限り、このイベント ハンドラーは、対応する方向移動状態を true に設定します。

OnKeyUp

void MoveLookController::OnKeyUp(
                                 __in CoreWindow^ sender,
                                 __in KeyEventArgs^ args)
{
    Windows::System::VirtualKey Key;
    Key = args->VirtualKey;

    // Figure out the command from the keyboard.
    if ( Key == VirtualKey::W )     // forward
        m_forward = false;
    if ( Key == VirtualKey::S )     // back
        m_back = false;
    if ( Key == VirtualKey::A )     // left
        m_left = false;
    if ( Key == VirtualKey::D )     // right
        m_right = false;
}

また、キーが解放されると、このイベント ハンドラーによって false に戻されます。 Updateを呼び出すと、これらの方向の移動状態がチェックされ、それに応じてカメラが移動されます。 これはタッチ実装よりも少し簡単です。

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

ここでイベントをフックし、すべてのコントローラー状態フィールドを初期化しましょう。

初期化する

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

    // Opt in to receive touch/mouse events.
    window->PointerPressed += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &MoveLookController::OnPointerPressed);

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

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

    window->CharacterReceived +=
    ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &MoveLookController::OnCharacterReceived);

    window->KeyDown += 
    ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &MoveLookController::OnKeyDown);

    window->KeyUp += 
    ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &MoveLookController::OnKeyUp);

    // Initialize the state of the controller.
    m_moveInUse = FALSE;                // No pointer is in the Move control.
    m_movePointerID = 0;

    m_lookInUse = FALSE;                // No pointer is in the Look control.
    m_lookPointerID = 0;

    //  Need to init this as it is reset every frame.
    m_moveCommand = DirectX::XMFLOAT3( 0.0f, 0.0f, 0.0f );

    SetOrientation( 0, 0 );             // Look straight ahead when the app starts.

}

Initialize は、アプリの CoreWindow インスタンスへの参照をパラメーターとして使い、先ほど作成したイベント ハンドラーをその CoreWindow の適切なイベントに登録します。 移動ポインターとルック ポインターの ID を初期化し、タッチ スクリーン移動コントローラーの実装のコマンド ベクターを 0 に設定し、アプリの起動時にカメラをまっすぐに見て設定します。

カメラの位置と向きの取得と設定

ビューポートに対してカメラの位置を取得および設定するメソッドをいくつか定義しましょう。

void MoveLookController::SetPosition( _In_ DirectX::XMFLOAT3 pos )
{
    m_position = pos;
}

// Accessor to set the position of the controller.
void MoveLookController::SetOrientation( _In_ float pitch, _In_ float yaw )
{
    m_pitch = pitch;
    m_yaw = yaw;
}

// Returns the position of the controller object.
DirectX::XMFLOAT3 MoveLookController::get_Position()
{
    return m_position;
}

// Returns the point at which the camera controller is facing.
DirectX::XMFLOAT3 MoveLookController::get_LookPoint()
{
    float y = sinf(m_pitch);        // Vertical
    float r = cosf(m_pitch);        // In the plane
    float z = r*cosf(m_yaw);        // Fwd-back
    float x = r*sinf(m_yaw);        // Left-right
    DirectX::XMFLOAT3 result(x,y,z);
    result.x += m_position.x;
    result.y += m_position.y;
    result.z += m_position.z;

    // Return m_position + DirectX::XMFLOAT3(x, y, z);
    return result;
}

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

次は、m_movePointerPosition で追跡したポインターの座標情報を、ワールド座標系における新しい座標情報に変換する計算を実行します。 Windows ストア アプリは、アプリのメイン ループが更新されるたびに、このメソッドを呼び出します。 そこで、ビューポートに投影する前にビュー マトリックスを更新するためにアプリに渡す新しいルック ポイントの位置情報を計算します。

void MoveLookController::Update(CoreWindow ^window)
{
    // Check for input from the Move control.
    if (m_moveInUse)
    {
        DirectX::XMFLOAT2 pointerDelta(m_movePointerPosition);
        pointerDelta.x -= m_moveFirstDown.x;
        pointerDelta.y -= m_moveFirstDown.y;

        // Figure out the command from the touch-based virtual joystick.
        if (pointerDelta.x > 16.0f)      // Leave 32 pixel-wide dead spot for being still.
            m_moveCommand.x = 1.0f;
        else
            if (pointerDelta.x < -16.0f)
            m_moveCommand.x = -1.0f;

        if (pointerDelta.y > 16.0f)      // Joystick y is up, so change sign.
            m_moveCommand.y = -1.0f;
        else
            if (pointerDelta.y < -16.0f)
            m_moveCommand.y = 1.0f;
    }

    // Poll our state bits that are set by the keyboard input events.
    if (m_forward)
        m_moveCommand.y += 1.0f;
    if (m_back)
        m_moveCommand.y -= 1.0f;

    if (m_left)
        m_moveCommand.x -= 1.0f;
    if (m_right)
        m_moveCommand.x += 1.0f;

    if (m_up)
        m_moveCommand.z += 1.0f;
    if (m_down)
        m_moveCommand.z -= 1.0f;

    // Make sure that 45 degree cases are not faster.
    DirectX::XMFLOAT3 command = m_moveCommand;
    DirectX::XMVECTOR vector;
    vector = DirectX::XMLoadFloat3(&command);

    if (fabsf(command.x) > 0.1f || fabsf(command.y) > 0.1f || fabsf(command.z) > 0.1f)
    {
        vector = DirectX::XMVector3Normalize(vector);
        DirectX::XMStoreFloat3(&command, vector);
    }
    

    // Rotate command to align with our direction (world coordinates).
    DirectX::XMFLOAT3 wCommand;
    wCommand.x = command.x*cosf(m_yaw) - command.y*sinf(m_yaw);
    wCommand.y = command.x*sinf(m_yaw) + command.y*cosf(m_yaw);
    wCommand.z = command.z;

    // Scale for sensitivity adjustment.
    wCommand.x = wCommand.x * MOVEMENT_GAIN;
    wCommand.y = wCommand.y * MOVEMENT_GAIN;
    wCommand.z = wCommand.z * MOVEMENT_GAIN;

    // Our velocity is based on the command.
    // Also note that y is the up-down axis. 
    DirectX::XMFLOAT3 Velocity;
    Velocity.x = -wCommand.x;
    Velocity.z = wCommand.y;
    Velocity.y = wCommand.z;

    // Integrate
    m_position.x += Velocity.x;
    m_position.y += Velocity.y;
    m_position.z += Velocity.z;

    // Clear movement input accumulator for use during the next frame.
    m_moveCommand = DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f);

}

プレイヤーがタッチベースの移動コントローラーを使用する場合は、ジッター移動を望まないため、直径 32 ピクセルのポインターの周りに仮想デッド ゾーンを設定します。 また、速度も追加します。これは、コマンド値に移動ゲインレートを加えた値です。 (この動作を好みに合わせて調整して、ポインターが移動コントローラー領域で移動する距離に基づいて移動速度を遅くしたり、速度を上げたりすることができます)。

速度を計算するときに、移動コントローラーとルック コントローラーから受け取った座標を、シーンのビュー マトリックスを計算するメソッドに送信する実際のルック ポイントの動きにも変換します。 まず、x 座標を反転します。これは、ルック コントローラーを使用して左または右にクリック移動またはドラッグすると、カメラが中心軸を中心に揺れる可能性があるため、シーン内でルック ポイントが逆方向に回転するためです。 次に、y 軸と z 軸を入れ替えます。これは、上/下キーを押すかタッチドラッグモーション (y 軸の動作として読み取る) を、画面の外観ポイント (z 軸) に移動するカメラ アクションに変換する必要があるためです。

プレイヤーの視点の最後の位置は、計算された速度を最後の位置に加えたものであり、この位置は、レンダラーが get_Position メソッドを呼び出すときにレンダラーが読み取ります (通常は各フレームのセットアップ中)。 その後、move コマンドを 0 にリセットします。

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

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

myMoveLookController->Update( m_window );   

// Update the view matrix based on the camera position.
myFirstPersonCamera->SetViewParameters(
                 myMoveLookController->get_Position(),       // Point we are at
                 myMoveLookController->get_LookPoint(),      // Point to look towards
                 DirectX::XMFLOAT3( 0, 1, 0 )                   // Up-vector
                 ); 

お疲れさまでした。 タッチ スクリーンとキーボード/マウス入力タッチ コントロールの両方の基本的なムーブルック コントロールをゲームに実装しました。