Bagikan melalui


Kontrol sentuh untuk game

Pelajari cara menambahkan kontrol sentuh dasar ke game C++ Platform Windows Universal (UWP) Anda dengan DirectX. Kami menunjukkan kepada Anda cara menambahkan kontrol berbasis sentuhan untuk memindahkan kamera bidang tetap di lingkungan Direct3D, di mana menyeret dengan jari atau stylus menggeser perspektif kamera.

Anda dapat menggabungkan kontrol ini dalam game di mana Anda ingin pemain menyeret untuk menggulir atau menggeser lingkungan 3D, seperti peta atau lapangan bermain. Misalnya, dalam strategi atau permainan teka-teki, Anda dapat menggunakan kontrol ini untuk memungkinkan pemain melihat lingkungan permainan yang lebih besar dari layar dengan menggeser ke kiri atau kanan.

Catatan Kode kami juga berfungsi dengan kontrol panning berbasis mouse. Peristiwa terkait pointer diabstraksi oleh WINDOWS Runtime API, sehingga dapat menangani peristiwa pointer berbasis sentuhan atau mouse.

 

Tujuan

  • Buat kontrol seret sentuhan sederhana untuk menggeser kamera bidang tetap dalam game DirectX.

Menyiapkan infrastruktur peristiwa sentuhan dasar

Pertama, kami mendefinisikan jenis pengontrol dasar kami, CameraPanController, dalam hal ini. Di sini, kami mendefinisikan pengontrol sebagai ide abstrak, serangkaian perilaku yang dapat dilakukan pengguna.

Kelas CameraPanController adalah kumpulan informasi yang disegarkan secara teratur tentang status pengontrol kamera, dan menyediakan cara bagi aplikasi kami untuk mendapatkan informasi tersebut dari perulangan pembaruannya.

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 CameraPanController
{
}

Sekarang, mari kita buat header yang menentukan status pengontrol kamera, dan metode dasar dan penanganan aktivitas yang mengimplementasikan interaksi pengontrol kamera.

ref class CameraPanController
{
private:
    // Properties of the controller object
    DirectX::XMFLOAT3 m_position;               // the position of the camera

    // Properties of the camera pan control
    bool m_panInUse;                
    uint32 m_panPointerID;          
    DirectX::XMFLOAT2 m_panFirstDown;           
    DirectX::XMFLOAT2 m_panPointerPosition;   
    DirectX::XMFLOAT3 m_panCommand;         
    
internal:
    // Accessor to set the position of the controller
    void SetPosition( _In_ DirectX::XMFLOAT3 pos );

       // Accessor to set the fixed "look point" of the controller
       DirectX::XMFLOAT3 get_FixedLookPoint();

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

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

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

};  // Class CameraPanController

Bidang privat berisi status pengontrol kamera saat ini. Mari kita tinjau.

  • m_position adalah posisi kamera di ruang adegan. Dalam contoh ini, nilai z-coordinate ditetapkan pada 0. Kita dapat menggunakan DirectX::XMFLOAT2 untuk mewakili nilai ini, tetapi untuk tujuan sampel ini dan ekstensibilitas di masa mendatang, kita menggunakan DirectX::XMFLOAT3. Kami meneruskan nilai ini melalui properti get_Position ke aplikasi itu sendiri sehingga dapat memperbarui viewport yang sesuai.
  • m_panInUse adalah nilai Boolean yang menunjukkan apakah operasi pan aktif; atau, lebih khusus lagi, apakah pemutar menyentuh layar dan menggerakkan kamera.
  • m_panPointerID adalah ID unik untuk penunjuk. Kami tidak akan menggunakan ini dalam sampel, tetapi ini adalah praktik yang baik untuk mengaitkan kelas status pengontrol Anda dengan pointer tertentu.
  • m_panFirstDown adalah titik pada layar di mana pemutar pertama kali menyentuh layar atau mengklik mouse selama aksi pandang kamera. Kami menggunakan nilai ini nanti untuk mengatur zona mati untuk mencegah jitter saat layar disentuh, atau jika mouse sedikit gemetar.
  • m_panPointerPosition adalah titik pada layar di mana pemutar saat ini telah memindahkan pointer. Kami menggunakannya untuk menentukan arah apa pemain ingin bergerak dengan memeriksanya relatif terhadap m_panFirstDown.
  • m_panCommand adalah perintah komputasi akhir untuk pengontrol kamera: atas, bawah, kiri, atau kanan. Karena kita bekerja dengan kamera yang diperbaiki ke bidang x-y, ini bisa menjadi nilai DirectX::XMFLOAT2 sebagai gantinya.

Kami menggunakan 3 penanganan aktivitas ini untuk memperbarui info status pengontrol kamera.

  • OnPointerPressed adalah penanganan aktivitas yang dipanggil aplikasi kami ketika pemain menekan jari ke permukaan sentuh dan penunjuk dipindahkan ke koordinat pers.
  • OnPointerMoved adalah penanganan aktivitas yang dipanggil aplikasi kami saat pemutar menggesekkan jari di seluruh permukaan sentuh. Ini diperbarui dengan koordinat baru jalur seret.
  • OnPointerReleased adalah penanganan aktivitas yang dipanggil aplikasi kami saat pemutar menghapus jari yang menekan dari permukaan sentuh.

Terakhir, kami menggunakan metode dan properti ini untuk menginisialisasi, mengakses, dan memperbarui informasi status pengontrol kamera.

  • Inisialisasi adalah penanganan aktivitas yang dipanggil aplikasi kami untuk menginisialisasi kontrol dan melampirkannya ke objek CoreWindow yang menjelaskan jendela tampilan Anda.
  • SetPosition adalah metode yang dipanggil aplikasi kami untuk mengatur koordinat (x, y, dan z) kontrol Anda di ruang adegan. Perhatikan bahwa koordinat z kami adalah 0 sepanjang tutorial ini.
  • get_Position adalah properti yang diakses aplikasi kami untuk mendapatkan posisi kamera saat ini di ruang adegan. Anda menggunakan properti ini sebagai cara mengkomunikasikan posisi kamera saat ini ke aplikasi.
  • get_FixedLookPoint adalah properti yang diakses aplikasi kami untuk mendapatkan titik saat ini ke arah yang dihadapi kamera pengontrol. Dalam contoh ini, dikunci normal ke bidang x-y.
  • Pembaruan adalah metode yang membaca status pengontrol dan memperbarui posisi kamera. Anda terus menyebutnya <sesuatu> 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 menerapkan kontrol sentuh. Anda dapat mendeteksi kapan dan di mana peristiwa sentuhan atau penunjuk mouse terjadi, dan apa tindakannya. Anda dapat mengatur posisi dan orientasi kamera relatif terhadap ruang adegan, dan melacak perubahan. Terakhir, Anda dapat mengkomunikasikan posisi kamera baru ke aplikasi panggilan.

Sekarang, mari kita hubungkan potongan-potongan ini bersama-sama.

Membuat peristiwa sentuhan dasar

Dispatcher peristiwa Windows Runtime menyediakan 3 peristiwa yang kami inginkan untuk ditangani oleh aplikasi kami:

Peristiwa ini diimplementasikan pada jenis CoreWindow . Kami berasumsi bahwa Anda memiliki objek CoreWindow untuk dikerjakan. Untuk informasi selengkapnya, lihat Cara menyiapkan aplikasi UWP C++ Anda untuk menampilkan tampilan DirectX.

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

Pertama, mari kita isi penanganan aktivitas penunjuk sentuh. Di penanganan aktivitas pertama, OnPointerPressed, kami mendapatkan koordinat x-y dari pointer dari CoreWindow yang mengelola tampilan kami saat pengguna menyentuh layar atau mengklik mouse.

OnPointerPressed

void CameraPanController::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 ( !m_panInUse )   // If no pointer is in this control yet.
    {
       m_panFirstDown = position;                   // Save the location of the initial contact.
       m_panPointerPosition = position;
       m_panPointerID = pointerID;              // Store the id of the pointer using this control.
       m_panInUse = TRUE;
    }
    
}

Kami menggunakan handler ini untuk memberi tahu instans CameraPanController saat ini bahwa pengontrol kamera harus diperlakukan aktif dengan mengatur m_panInUse ke TRUE. Dengan begitu, ketika aplikasi memanggil Update , aplikasi akan menggunakan data posisi saat ini untuk memperbarui viewport.

Sekarang setelah kita menetapkan nilai dasar untuk pergerakan kamera ketika pengguna menyentuh layar atau mengklik-tekan di jendela tampilan, kita harus menentukan apa yang harus dilakukan ketika pengguna menyeret layar tekan atau menggerakkan mouse dengan tombol ditekan.

Penanganan aktivitas OnPointerMoved diaktifkan setiap kali penunjuk bergerak, di setiap tanda centang bahwa pemutar menyeretnya ke layar. Kita perlu menjaga aplikasi tetap mengetahui lokasi pointer saat ini, dan ini adalah cara kita melakukannya.

OnPointerMoved

void CameraPanController::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 );

    m_panPointerPosition = position;
}

Akhirnya, kita perlu menonaktifkan perilaku panci kamera ketika pemutar berhenti menyentuh layar. Kami menggunakan OnPointerReleased, yang dipanggil ketika PointerReleased diaktifkan, untuk mengatur m_panInUse ke FALSE dan menonaktifkan gerakan pan kamera, dan mengatur ID penunjuk ke 0.

OnPointerReleased

void CameraPanController::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 );

    m_panInUse = FALSE;
    m_panPointerID = 0;
}

Menginisialisasi kontrol sentuh dan status pengontrol

Mari kita kaitkan peristiwa dan inisialisasi semua bidang status dasar pengontrol kamera.

Initialize

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

    // Start receiving 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 the state of the controller.
    m_panInUse = FALSE;             
    m_panPointerID = 0;

    //  Initialize this as it is reset on every frame.
    m_panCommand = DirectX::XMFLOAT3( 0.0f, 0.0f, 0.0f );

}

Inisialisasi mengambil referensi ke instans CoreWindow aplikasi sebagai parameter dan mendaftarkan penanganan aktivitas yang kami kembangkan ke peristiwa yang sesuai pada CoreWindow tersebut.

Mendapatkan dan mengatur posisi pengontrol kamera

Mari kita tentukan beberapa metode untuk mendapatkan dan mengatur posisi pengontrol kamera di ruang adegan.

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

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

DirectX::XMFLOAT3 CameraPanController::get_FixedLookPoint()
{
    // For this sample, we don't need to use the trig functions because our
    // look point is fixed. 
    DirectX::XMFLOAT3 result= m_position;
    result.z += 1.0f;
    return result;    

}

SetPosition adalah metode publik yang dapat kita panggil dari aplikasi jika kita perlu mengatur posisi pengontrol kamera ke titik tertentu.

get_Position adalah properti publik kami yang paling penting: ini adalah cara aplikasi kami mendapatkan posisi pengontrol kamera saat ini di ruang adegan sehingga dapat memperbarui viewport yang sesuai.

get_FixedLookPoint adalah properti publik yang, dalam contoh ini, mendapatkan titik tampilan yang normal untuk bidang x-y. Anda dapat mengubah metode ini untuk menggunakan fungsi trigonometri, sin dan cos, saat menghitung nilai koordinat x, y, dan z jika Anda ingin membuat sudut yang lebih miring untuk kamera tetap.

Memperbarui informasi status pengontrol kamera

Sekarang, kami melakukan perhitungan kami yang mengonversi info koordinat pointer yang dilacak dalam m_panPointerPosition menjadi info koordinat baru masing-masing dari ruang adegan 3D kami. Aplikasi kami memanggil metode ini setiap kali kami merefresh perulangan aplikasi utama. Di dalamnya kita menghitung informasi posisi baru yang ingin kita teruskan ke aplikasi yang digunakan untuk memperbarui matriks tampilan sebelum proyeksi ke viewport.


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

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

       DirectX::XMFLOAT3 command = m_panCommand;
   
    // Our velocity is based on the command.
    DirectX::XMFLOAT3 Velocity;
    Velocity.x =  command.x;
    Velocity.y =  command.y;
    Velocity.z =  0.0f;

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

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

}

Karena kita tidak ingin sentuhan atau jitter mouse membuat kamera kita menggeser dendeng, kita mengatur zona mati di sekitar pointer dengan diameter 32 piksel. Kami juga memiliki nilai kecepatan, yang dalam hal ini adalah 1:1 dengan traversal piksel pointer melewati zona mati. Anda dapat menyesuaikan perilaku ini untuk memperlambat atau mempercepat laju pergerakan.

Memperbarui matriks tampilan dengan posisi kamera baru

Kita sekarang dapat memperoleh koordinat ruang adegan yang difokuskan kamera kita, 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:

 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.
        DirectX::XMFLOAT3( 0, 1, 0 )                    // The axis that is "up" in our space.
        );  

Selamat! Anda telah menerapkan serangkaian kontrol sentuh panning kamera sederhana dalam permainan Anda.