瞭解如何將傳統的滑鼠和鍵盤移動外觀控制項(也稱為 mouselook 控件)新增至 DirectX 遊戲。
我們也會討論觸控裝置的移動與視覺控制支援,移動控制器被定義為螢幕左下角的區域,行為類似於方向輸入,而視覺控制器則定義於螢幕的其他部分,相機會置中於玩家在該區域最後一次觸碰的地方。
如果這對你來說是不熟悉的控制概念,請以這種方式思考:鍵盤(或觸控型方向輸入方塊)在這個3D空間中控制您的腿部,這種操作方式就像您的腿只能夠向前或向後移動,或向左或向右平移。 滑鼠(或觸控指標)控制您的頭部。 您可以使用頭部往左或向右、向上或向下或在該平面的某處看。 如果您的視野中有目標,您可以使用滑鼠將相機畫面對準該目標,然後按前進鍵朝它移動,或按後退鍵遠離它。 若要環繞目標,您會將相機視角維持在目標上置中,同時向左或向右移動。 您可以看到這是一種在 3D 環境中非常有效的導航控制方法!
這些控件通常稱為遊戲中的 WASD 控件,其中 W、A、S 和 D 鍵用於 x-z 平面固定相機移動,而滑鼠則用來控制相機繞 x 軸和 y 軸旋轉。
目標
- 將基本的移動和視角控制新增到您的 DirectX 遊戲中,適用於滑鼠、鍵盤以及觸控螢幕。
- 實作用來巡覽 3D 環境的第一人稱攝影機。
觸控控件實作的注意事項
針對觸控控制,我們實作了兩個控制器:移動控制器,負責處理 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 值時,我們會使用它來區分查看指標和移動指標。
- m_moveFirstDown 是玩家第一次觸碰移動控制器指標區域的螢幕上的點。 我們稍後會使用此值來設置一個死區,以防止微小的動作導致視圖抖動。
- m_movePointerPosition 是玩家目前已將指標移至的螢幕上的點。 我們使用它來判斷玩家想要移動的方向,方法是將其與 m_moveFirstDown進行比較。
- m_moveCommand 是移動控制器的最終計算命令:向上(向前)、向下(後)、向左或向右。
現在,我們來定義用於操控視覺控制器的欄位,包括滑鼠和觸控的實現。
- m_lookInUse 指出外觀控制件是否正在使用中。
- m_lookPointerID 是目前外觀指標的唯一標識符。 當我們檢查指標 ID 值時,我們會使用它來區分查看指標和移動指標。
- m_lookLastPoint 是在上一個畫面格中擷取的,位於場景座標的最後一個點。
- m_lookLastDelta 是目前 m_position 與 m_lookLastPoint之間的計算差異。
最後,我們會針對 6 度移動定義 6 個布爾值,我們用來指出每個方向移動動作的目前狀態(開啟或關閉):
- m_forward、m_back、m_left、m_right、m_up 和 m_down。
我們使用 6 個事件處理程式來擷取我們用來更新控制器狀態的輸入資料:
- OnPointerPressed。 玩家在遊戲畫面中使用指標按下滑鼠左鍵,或觸碰螢幕。
- OnPointerMoved。 玩家在遊戲畫面中使用指標移動滑鼠,或拖曳螢幕上的觸控指標。
- 當指針釋放。 玩家在遊戲畫面中放開滑鼠左鍵,或停止觸碰螢幕。
- OnKeyDown。 玩家按下按鍵。
- OnKeyUp。 玩家放開了一把鑰匙。
最後,我們會使用這些方法和屬性來初始化、存取和更新控制器的狀態資訊。
- 初始化。 我們的應用程式會呼叫這個事件處理程式來初始化控件,並將其附加至描述顯示視窗的 CoreWindow 物件。
- 設定位置。 我們的應用程式會呼叫此方法,以在場景空間中設定控件的 (x、y 和 z) 座標。
- SetOrientation。 我們的應用程式會呼叫此方法來設定相機的俯仰角和偏航角。
- get_Position。 我們的應用程式會存取此屬性,以取得場景空間中相機的目前位置。 您可以使用這個屬性作為將目前相機位置與應用程式通訊的方法。
- get_LookPoint。 我們的應用程式會存取此屬性,以取得控制器相機面對的目前點。
- Update。 讀取移動和視角控制器的狀態,並更新相機位置。 您不斷從應用程式的主要迴圈呼叫此方法,以重新整理相機控制器數據和場景空間中的相機位置。
現在,您在這裡擁有實作移動和視角控制所需的所有元件。 因此,讓我們將這些部分連接在一起。
建立基本輸入事件
Windows 執行階段事件發送器提供 5 個事件,我們希望 MoveLookController 類別的實例來處理:
這些事件會在 CoreWindow 類型上實作。 我們假設您有一個 CoreWindow 物件可使用。 如果您不知道如何取得它,請參閱 如何設置通用 Windows 平台 (UWP) C++ 應用程式以顯示 DirectX 視圖。
當應用程式執行時引發這些事件時,處理程式會更新我們私用字段中定義的控制器狀態資訊。
首先,讓我們填入滑鼠和觸控指標事件處理程式。 在第一個事件處理程式中,OnPointerPressed(),我們會從 CoreWindow 取得指標的 x-y 坐標,當使用者按兩下滑鼠或觸碰外觀控制器區域中的畫面時,管理我們的顯示。
按下指針時
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;
}
}
}
這個事件處理程式會檢查指標是否不是滑鼠(此範例支援滑鼠和觸控),以及它是否位於行動控制器區域中。 如果這兩個準則都成立,它會藉由測試 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 事件處理程式。在這種情況下,這包括拖曳觸控屏幕指標,或在按下左鍵的同時移動滑鼠指標。 如果指標標識碼與移動控制器指標的標識符相同,則它是移動指標;否則,我們會檢查是否是視角控制器作為作用中指標。
如果是移動控制器,我們只會更新指標位置。 只要 PointerMoved 事件持續引發,我們會持續更新它,因為我們想要將最後一個位置與 OnPointerPressed 事件處理程式所擷取的第一個位置進行比較。
如果它指的是控制外觀的裝置,事情會稍微複雜一點。 我們需要計算一個新的觀察點並將相機對準它的中心,所以我們會計算最後一個觀察點與目前螢幕位置之間的差異,然後乘上我們的縮放係數,我們可以調整這個係數,使觀察點移動相對於螢幕移動距離變得更小或更大。 使用該值,我們計算俯仰角和偏航角。
最後,當玩家停止移動滑鼠或觸碰螢幕時,我們需要停用移動或視覺控制器行為。 我們使用
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上的適當事件。 它會初始化移動和視角指標的識別碼,將觸控螢幕移動控制器的命令向量設定為零,並在應用程式啟動時將相機設定為正前方。
取得和設定相機的位置和方向
讓我們定義一些方法來取得和設定相機相對於檢視區的位置。
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 中所追蹤的指標座標資訊轉換成我們世界座標系統的新座標資訊。 每次重新整理主要應用程式迴圈時,我們的應用程式都會呼叫此方法。 因此,我們在這裡計算新的視點位置資訊,我們想要將這些資訊傳遞給應用程式,以便在投影到檢視窗之前更新視圖矩陣。
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命令重設為零。
使用新的相機位置更新檢視矩陣
我們可以取得相機聚焦的場景空間座標,並且每當您告訴您的應用程式如此時,它都會更新(例如,在主要程式迴圈中每 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
);
祝賀! 在您的遊戲中,您已實作了針對觸摸屏與鍵盤/滑鼠輸入的基本移動與視角控制!