Bagikan melalui


Kontrol tampilan pemindahan untuk game

Pelajari cara menambahkan kontrol tampilan bergerak mouse dan keyboard tradisional (juga dikenal sebagai kontrol mouselook) ke game DirectX Anda.

Kami juga membahas dukungan move-look untuk perangkat sentuh, dengan pengontrol pemindahan yang didefinisikan sebagai bagian kiri bawah layar yang bertingkah seperti input terarah, dan pengontrol tampilan yang didefinisikan untuk sisa layar, dengan kamera berpusat di tempat terakhir pemutar disentuh di area tersebut.

Jika ini adalah konsep kontrol yang tidak terbiasa bagi Anda, anggap saja dengan cara ini: keyboard (atau kotak input arah berbasis sentuhan) mengontrol kaki Anda di ruang 3D ini, dan bertingkah seolah-olah kaki Anda hanya mampu bergerak maju atau mundur, atau menyimpang ke kiri dan kanan. Mouse (atau penunjuk sentuh) mengontrol kepala Anda. Anda menggunakan kepala untuk melihat ke arah -- kiri atau kanan, atas atau bawah, atau di suatu tempat di bidang itu. Jika ada target dalam tampilan Anda, Anda akan menggunakan mouse untuk memusatkan tampilan kamera Anda pada target tersebut, lalu tekan tombol maju untuk bergerak ke arahnya, atau kembali untuk menjauh darinya. Untuk melingkari target, Anda akan menjaga tampilan kamera tetap terpusat pada target, dan bergerak ke kiri atau kanan secara bersamaan. Anda dapat melihat bagaimana ini adalah metode kontrol yang sangat efektif untuk menavigasi lingkungan 3D!

Kontrol ini umumnya dikenal sebagai kontrol WASD dalam game, di mana tombol W, A, S, dan D digunakan untuk gerakan kamera tetap bidang x-z, dan mouse digunakan untuk mengontrol rotasi kamera di sekitar sumbu x dan y.

Tujuan

  • Tambahkan kontrol tampilan pemindahan dasar ke game DirectX Anda untuk mouse dan keyboard, dan layar sentuh.
  • Terapkan kamera orang pertama yang digunakan untuk menavigasi lingkungan 3D.

Catatan tentang implementasi kontrol sentuh

Untuk kontrol sentuh, kami menerapkan dua pengontrol: pengontrol pemindahan, yang menangani gerakan di bidang x-z relatif terhadap titik tampilan kamera; dan pengontrol tampilan, yang bertujuan titik tampilan kamera. Pengontrol pemindahan kami memetakan ke tombol WASD keyboard, dan tampilan pengontrol memetakan ke mouse. Tetapi untuk kontrol sentuh, kita perlu mendefinisikan wilayah layar yang berfungsi sebagai input terarah, atau tombol WASD virtual, dengan sisa layar berfungsi sebagai ruang input untuk kontrol tampilan.

Layar kami terlihat seperti ini.

tata letak pengontrol tampilan pemindahan

Saat Anda menggerakkan penunjuk sentuh (bukan mouse!) di kiri bawah layar, gerakan apa pun ke atas akan membuat kamera bergerak maju. Setiap gerakan ke bawah akan membuat kamera bergerak mundur. Hal yang sama berlaku untuk gerakan kiri dan kanan di dalam ruang penunjuk pengontrol pemindahan. Di luar ruang itu, dan itu menjadi pengontrol tampilan -- Anda cukup menyentuh atau menyeret kamera ke tempat yang Anda inginkan untuk menghadap.

Menyiapkan infrastruktur peristiwa input dasar

Pertama, kita harus membuat kelas kontrol yang kita gunakan untuk menangani peristiwa input dari mouse dan keyboard, dan memperbarui perspektif kamera berdasarkan input tersebut. Karena kami menerapkan kontrol move-look, kami menyebutnya 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

Sekarang, mari kita buat header yang menentukan status pengontrol tampilan pemindahan dan kamera orang pertamanya, ditambah metode dasar dan penanganan aktivitas yang mengimplementasikan kontrol dan yang memperbarui status kamera.

#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

Kode kami berisi 4 grup bidang privat. Mari kita tinjau tujuan masing-masing.

Pertama, kami mendefinisikan beberapa bidang berguna yang menyimpan info terbaru tentang tampilan kamera kami.

  • m_position adalah posisi kamera (dan oleh karena itu viewplane) di adegan 3D, menggunakan koordinat adegan.
  • m_pitch adalah pitch kamera, atau rotasi up-down di sekitar sumbu x viewplane, dalam radian.
  • m_yaw adalah yaw kamera, atau rotasi kanan kiri di sekitar sumbu y viewplane, dalam radian.

Sekarang, mari kita tentukan bidang yang kita gunakan untuk menyimpan info tentang status dan posisi pengontrol kita. Pertama, kita akan menentukan bidang yang kita butuhkan untuk pengontrol pemindahan berbasis sentuhan kita. (Tidak ada yang diperlukan khusus untuk implementasi keyboard pengontrol pemindahan. Kami hanya membaca peristiwa keyboard dengan handler tertentu.)

  • m_moveInUse menunjukkan apakah pengontrol pemindahan sedang digunakan.
  • m_movePointerID adalah ID unik untuk penunjuk pemindahan saat ini. Kami menggunakannya untuk membedakannya antara penunjuk tampilan dan penunjuk pemindahan saat kami memeriksa nilai ID penunjuk.
  • m_moveFirstDown adalah titik pada layar di mana pemutar pertama kali menyentuh area pointer pengontrol pemindahan. Kami menggunakan nilai ini nanti untuk mengatur zona mati untuk menjaga gerakan kecil dari jittering tampilan.
  • m_movePointerPosition adalah titik pada layar tempat pemutar saat ini telah memindahkan penunjuk. Kami menggunakannya untuk menentukan arah yang diinginkan pemain untuk bergerak dengan memeriksanya relatif terhadap m_moveFirstDown.
  • m_moveCommand adalah perintah komputasi akhir untuk pengontrol pemindahan: atas (maju), bawah (belakang), kiri, atau kanan.

Sekarang, kita mendefinisikan bidang yang kita gunakan untuk pengontrol tampilan kita, baik implementasi mouse maupun sentuhan.

  • m_lookInUse menunjukkan apakah kontrol tampilan sedang digunakan.
  • m_lookPointerID adalah ID unik untuk penunjuk tampilan saat ini. Kami menggunakannya untuk membedakannya antara penunjuk tampilan dan penunjuk pemindahan saat kami memeriksa nilai ID penunjuk.
  • m_lookLastPoint adalah titik terakhir, dalam koordinat adegan, yang ditangkap di bingkai sebelumnya.
  • m_lookLastDelta adalah perbedaan komputasi antara m_position saat ini dan m_lookLastPoint.

Akhirnya, kita mendefinisikan 6 nilai Boolean untuk 6 derajat gerakan, yang kita gunakan untuk menunjukkan status saat ini dari setiap tindakan pemindahan arah (aktif atau nonaktif):

  • m_forward, m_back, m_left, m_right, m_up dan m_down.

Kami menggunakan 6 penanganan aktivitas untuk menangkap data input yang kami gunakan untuk memperbarui status pengontrol kami:

  • OnPointerPressed. Pemain menekan tombol mouse kiri dengan penunjuk di layar permainan kami, atau menyentuh layar.
  • OnPointerMoved. Pemain menggerakkan mouse dengan penunjuk di layar permainan kami, atau menyeret penunjuk sentuh di layar.
  • OnPointerReleased. Pemain melepaskan tombol mouse kiri dengan penunjuk di layar permainan kami, atau berhenti menyentuh layar.
  • OnKeyDown. Pemutar menekan tombol.
  • OnKeyUp. Pemutar merilis kunci.

Dan akhirnya, kami menggunakan metode dan properti ini untuk menginisialisasi, mengakses, dan memperbarui info status pengontrol.

  • Inisialisasi. Aplikasi kami memanggil penanganan aktivitas ini untuk menginisialisasi kontrol dan melampirkannya ke objek CoreWindow yang menjelaskan jendela tampilan kami.
  • SetPosition. Aplikasi kami memanggil metode ini untuk mengatur koordinat (x, y, dan z) kontrol kami di ruang adegan.
  • SetOrientation. Aplikasi kami memanggil metode ini untuk mengatur nada dan yaw kamera.
  • get_Position. Aplikasi kami mengakses properti ini untuk mendapatkan posisi kamera saat ini di ruang adegan. Anda menggunakan properti ini sebagai metode untuk mengkomunikasikan posisi kamera saat ini ke aplikasi.
  • get_LookPoint. Aplikasi kami mengakses properti ini untuk mendapatkan titik saat ini yang dihadapi kamera pengontrol.
  • Perbarui. Membaca status pengontrol pemindahan dan tampilan dan memperbarui posisi kamera. Anda terus memanggil metode ini dari perulangan utama aplikasi untuk menyegarkan data pengontrol kamera dan posisi kamera di ruang adegan.

Sekarang, Anda memiliki di sini semua komponen yang Anda butuhkan untuk mengimplementasikan kontrol tampilan bergerak Anda. Jadi, mari kita hubungkan potongan-potongan ini bersama-sama.

Membuat peristiwa input dasar

Dispatcher peristiwa Windows Runtime menyediakan 5 peristiwa yang kami inginkan untuk ditangani instans kelas MoveLookController :

Peristiwa ini diimplementasikan pada jenis CoreWindow . Kami berasumsi bahwa Anda memiliki objek CoreWindow untuk dikerjakan. Jika Anda tidak tahu cara mendapatkannya, lihat Cara menyiapkan aplikasi C++ Platform Windows Universal (UWP) Anda untuk menampilkan tampilan DirectX.

Saat peristiwa ini diaktifkan saat aplikasi kami berjalan, handler memperbarui info status pengontrol yang ditentukan di bidang privat kami.

Pertama, mari kita isi penangan peristiwa mouse dan penunjuk sentuh. Di penanganan aktivitas pertama, OnPointerPressed(), kami mendapatkan koordinat x-y penunjuk dari CoreWindow yang mengelola tampilan kami ketika pengguna mengklik mouse atau menyentuh layar di wilayah pengontrol tampilan.

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

Penanganan aktivitas ini memeriksa apakah penunjuk bukan mouse (untuk tujuan sampel ini, yang mendukung mouse dan sentuh) dan jika berada di area pengontrol pemindahan. Jika kedua kriteria benar, ini memeriksa apakah penunjuk hanya ditekan, khususnya, apakah klik ini tidak terkait dengan input pemindahan atau tampilan sebelumnya, dengan menguji apakah m_moveInUse salah. Jika demikian, handler menangkap titik di area pengontrol pemindahan di mana pers terjadi dan mengatur m_moveInUse ke true, sehingga ketika handler ini dipanggil lagi, itu tidak akan menimpa posisi awal interaksi input pengontrol pemindahan. Ini juga memperbarui ID penunjuk pengontrol pemindahan ke ID penunjuk saat ini.

Jika penunjuk adalah mouse atau jika penunjuk sentuh tidak berada di area pengontrol pemindahan, penunjuk harus berada di area pengontrol tampilan. Ini mengatur m_lookLastPoint ke posisi saat ini di mana pengguna menekan tombol mouse atau menyentuh dan menekan, mengatur ulang delta, dan memperbarui ID penunjuk pengontrol tampilan ke ID penunjuk saat ini. Ini juga mengatur status pengontrol tampilan menjadi aktif.

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

Penanganan aktivitas OnPointerMoved diaktifkan setiap kali penunjuk bergerak (dalam hal ini, jika penunjuk layar sentuh sedang diseret, atau jika penunjuk mouse sedang dipindahkan saat tombol kiri ditekan). Jika ID penunjuk sama dengan ID penunjuk pengontrol pemindahan, maka id tersebut adalah penunjuk pemindahan; jika tidak, kami memeriksa apakah itu pengontrol tampilan yang merupakan penunjuk aktif.

Jika itu adalah pengontrol pemindahan, kita hanya memperbarui posisi pointer. Kami terus memperbaruinya selama peristiwa PointerMoved terus diaktifkan, karena kami ingin membandingkan posisi akhir dengan posisi pertama yang kami ambil dengan penanganan aktivitas OnPointerPressed .

Jika itu adalah pengontrol tampilan, hal-hal yang sedikit lebih rumit. Kita perlu menghitung titik tampilan baru dan tengahkan kamera di atasnya, jadi kita menghitung delta antara titik tampilan terakhir dan posisi layar saat ini, dan kemudian kita mengalikan versus faktor skala kita, yang dapat kita ubah untuk membuat gerakan tampilan lebih kecil atau lebih besar relatif terhadap jarak pergerakan layar. Dengan menggunakan nilai tersebut, kami menghitung pitch dan yaw.

Akhirnya, kita perlu menonaktifkan perilaku pengontrol pemindahan atau tampilan ketika pemutar berhenti menggerakkan mouse atau menyentuh layar. Kami menggunakan OnPointerReleased, yang kami panggil saat PointerReleased diaktifkan, untuk mengatur m_moveInUse atau m_lookInUse ke FALSE dan menonaktifkan gerakan panci kamera, dan untuk nol keluar ID penunjuk.

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

Sejauh ini, kami menangani semua peristiwa layar sentuh. Sekarang, mari kita tangani peristiwa input kunci untuk pengontrol pemindahan berbasis keyboard.

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

Selama salah satu tombol ini ditekan, penanganan aktivitas ini mengatur status pemindahan arah yang sesuai ke 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;
}

Dan ketika kunci dirilis, penanganan aktivitas ini mengaturnya kembali ke false. Ketika kita memanggil Perbarui, ini memeriksa status pemindahan arah ini, dan memindahkan kamera yang sesuai. Ini sedikit lebih sederhana daripada implementasi sentuhan!

Menginisialisasi kontrol sentuh dan status pengontrol

Mari kita hubungkan peristiwa sekarang, dan inisialisasi semua bidang status pengontrol.

Initialize

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.

}

Inisialisasi mengambil referensi ke instans CoreWindow aplikasi sebagai parameter dan mendaftarkan penanganan aktivitas yang kami kembangkan ke peristiwa yang sesuai pada CoreWindow tersebut. Ini menginisialisasi ID pemindahan dan tampilan pointer, mengatur vektor perintah untuk implementasi pengontrol pemindahan layar sentuh kita ke nol, dan mengatur kamera melihat lurus ke depan saat aplikasi dimulai.

Mendapatkan dan mengatur posisi dan orientasi kamera

Mari kita tentukan beberapa metode untuk mendapatkan dan mengatur posisi kamera sehubungan dengan viewport.

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

Memperbarui info status pengontrol

Sekarang, kami melakukan perhitungan kami yang mengonversi info koordinat pointer yang dilacak dalam m_movePointerPosition menjadi informasi koordinat baru masing-masing dari sistem koordinat dunia kami. Aplikasi kami memanggil metode ini setiap kali kami merefresh perulangan aplikasi utama. Jadi, di sinilah kita menghitung info posisi titik tampilan baru yang ingin kita teruskan ke aplikasi untuk memperbarui matriks tampilan sebelum proyeksi ke viewport.

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

}

Karena kami tidak ingin gerakan jittery ketika pemutar menggunakan pengontrol pemindahan berbasis sentuhan kami, kami mengatur zona mati virtual di sekitar pointer dengan diameter 32 piksel. Kami juga menambahkan kecepatan, yang merupakan nilai perintah ditambah tingkat perolehan pergerakan. (Anda dapat menyesuaikan perilaku ini sesuai keinginan Anda, untuk memperlambat atau mempercepat laju pergerakan berdasarkan jarak pergerakan penunjuk di area pengontrol pemindahan.)

Ketika kami menghitung kecepatan, kami juga menerjemahkan koordinat yang diterima dari pengontrol pemindahan dan tampilan ke dalam pergerakan titik tampilan aktual yang kami kirim ke metode yang menghitung matriks tampilan kami untuk adegan. Pertama, kita membalikkan koordinat x, karena jika kita klik-pindah atau seret ke kiri atau kanan dengan pengontrol tampilan, titik tampilan berputar ke arah yang berlawanan dalam adegan, karena kamera mungkin mengayun tentang sumbu pusatnya. Kemudian, kami menukar sumbu y dan z, karena tombol atas/bawah menekan atau menyentuh gerakan seret (dibaca sebagai perilaku sumbu y) pada pengontrol pemindahan harus diterjemahkan ke dalam tindakan kamera yang memindahkan titik tampilan ke atau ke luar layar (sumbu z).

Posisi akhir titik tampilan untuk pemutar adalah posisi terakhir ditambah kecepatan terhitung, dan inilah yang dibaca oleh perender ketika memanggil metode get_Position (kemungkinan besar selama penyiapan untuk setiap bingkai). Setelah itu, kita mengatur ulang perintah pindah ke nol.

Memperbarui matriks tampilan dengan posisi kamera baru

Kami dapat memperoleh koordinat ruang adegan yang difokuskan kamera kami, dan yang diperbarui setiap kali Anda memberi tahu aplikasi Anda untuk melakukannya (setiap 60 detik dalam perulangan aplikasi utama, misalnya). Pseudocode ini menyarankan perilaku panggilan yang dapat Anda terapkan:

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

Selamat! Anda telah menerapkan kontrol tampilan gerakan dasar untuk layar sentuh dan kontrol sentuh input keyboard/mouse dalam permainan Anda!