Aracılığıyla paylaş


Oyunlar için hareket ve görünüm denetimleri

DirectX oyununuza geleneksel fare ve klavye hareket-görüş kontrolleri (fareyle bakış kontrolleri olarak da bilinir) eklemeyi öğrenin.

Dokunmatik cihazlar için hareket ve bakış desteğini de ele alıyoruz. Ekranın sol alt köşesi yön girişi gibi davranan hareket denetleyicisi olarak tanımlanırken, geri kalan kısmı ise oyuncunun o alanda en son dokunduğu yere kameranın odaklandığı bakış denetleyicisi olarak tanımlanıyor.

Bu size tanıdık olmayan bir kontrol kavramıysa şu şekilde düşünün: klavye (ya da dokunmatik tabanlı yönlü giriş kutusu) bu 3B alanda bacaklarınızın kontrolünü sağlar ve bacaklarınız yalnızca ileri veya geri hareket edebilir ya da sola ve sağa doğru kayabilir gibi bir davranış sergiler. Fare (veya dokunma işaretçisi) başınızı denetler. Kafanı kullanarak sola veya sağa, yukarı veya aşağı ya da o uçakta bir yere bak. Görünümünüzde bir hedef varsa, fareyi kullanarak kamera görünümünüzü o hedefe ortalarsınız ve ardından ileri tuşuna basarak bu hedefe doğru hareket eder veya ondan uzaklaşmak için geri dönersiniz. Hedefin etrafında dönmek için kamera görünümünü hedefte tutarken bir yandan da sola veya sağa hareket etmelisiniz. Bunun 3B ortamlarda gezinmek için çok etkili bir denetim yöntemi olduğunu görebilirsiniz!

Bu denetimler genellikle oyunlarda WASD denetimleri olarak bilinir; burada W, A, S ve D tuşları x-z düzlem sabit kamera hareketi için kullanılır ve fare x ve y eksenleri etrafında kamera döndürmeyi denetlemek için kullanılır.

Hedef

  • DirectX oyununuza hem fare hem klavye hem de dokunmatik ekranlar için temel hareket görünümü denetimleri ekleyin.
  • 3B ortamda gezinmek için kullanılan birinci kişi kamerasını uygulayın.

Dokunmatik denetim uygulamalarıyla ilgili bir not

Dokunmatik kontroller için iki denetleyici uygularız: x-z düzlemindeki hareketi kameranın bakış noktasına göre işleyen taşıma denetleyicisi; ve kameranın bakış noktasını hedefleyen görünüm denetleyicisi. Taşıma kontrol cihazımız klavye WASD tuşlarıyla, görünüm kontrol cihazı ise fare ile eşleştirir. Ancak dokunmatik denetimler için, yönlü girişler veya sanal WASD düğmeleri işlevi gören ekranın bir bölgesini tanımlamamız ve ekranın geri kalanının da görünüm denetimleri için giriş alanı olarak hizmet etmesini sağlamamız gerekir.

Ekranımız şöyle görünüyor.

hareket-görüş denetleyici düzeni

Ekranın sol alt kısmındaki dokunma işaretçisini (fareyi değil!) hareket ettirdiğinizde, yukarı doğru herhangi bir hareket kamerayı ileri doğru hareket ettirecektir. Aşağı doğru herhangi bir hareket, kameranın geriye doğru hareket etmesini sağlar. Hareket denetleyicisinin işaretçi alanı içinde sola ve sağa hareket için aynısı geçerlidir. Bu alanın dışında, bir görünüm denetleyicisine dönüşür - sadece kameraya dokunmanız veya yönlendirmek istediğiniz yöne sürüklemeniz yeterli olur.

Temel giriş olayı altyapısını ayarlama

İlk olarak, fare ve klavyeden giriş olaylarını işlemek için kullandığımız denetim sınıfımızı oluşturmalı ve kamera perspektifini bu girişe göre güncelleştirmeliyiz. Move-Look kontrollerini uyguladığımız için, buna MoveLookControlleradını veriyoruz.

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

Şimdi, hareket-görüş denetleyicisinin ve birinci şahıs kamerasının durumunu tanımlayan bir başlık oluşturalım, ardından durumu güncelleyen ve denetimleri uygulayan temel yöntemler ve olay işleyicilerini ekleyelim.

#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

Kodumuz 4 özel alan grubu içerir. Şimdi her birinin amacını gözden geçirelim.

İlk olarak, kamera görünümümüzle ilgili güncel bilgilerimizi tutan bazı yararlı alanlar tanımlayacağız.

  • m_position , sahne koordinatlarını kullanarak kameranın (ve dolayısıyla görünüm düzleminin) 3B sahnedeki konumudur.
  • m_pitch, kameranın eğimi veya radyan cinsinden görünüm düzleminin x ekseni etrafında yukarı-aşağı dönüş açısıdır.
  • m_yaw, kameranın radyan cinsinden görünüm düzleminin y ekseni etrafında sola ve sağa döndürülmesidir.

Şimdi denetleyicilerimizin durumu ve konumu hakkında bilgi depolamak için kullandığımız alanları tanımlayalım. İlk olarak, dokunmatik tabanlı taşıma denetleyicimiz için ihtiyacımız olan alanları tanımlayacağız. (Hareket denetleyicisinin klavye uygulaması için özel bir şey gerekmez. Yalnızca klavye olaylarını belirli işleyicilerle okuyoruz.)

  • m_moveInUse taşıma denetleyicisinin kullanımda olup olmadığını gösterir.
  • m_movePointerID geçerli taşıma işaretçisinin benzersiz kimliğidir. İşaretçi kimliği değerini denetlediğimizde, görünüm işaretçisi ile taşıma işaretçisi arasında ayrım yapmak için bunu kullanırız.
  • m_moveFirstDown , ekranda oyuncunun ilk kez hareket denetleyicisi işaretçi alanına dokunduğu noktadır. Bu değeri daha sonra küçük hareketlerin görünümde titremesini engelleyebilecek bir ölü bölge ayarlamak için kullanırız.
  • m_movePointerPosition , oyuncunun işaretçiyi şu anda taşıdığı ekrandaki noktadır. Oyuncunun hareket etmek istediği yönü belirlemek için, onu m_moveFirstDownile karşılaştırarak kullanırız.
  • m_moveCommand , taşıma denetleyicisinin son hesaplanan komutudur: yukarı (ileri), aşağı (geri), sola veya sağa.

Şimdi, hem fare hem de dokunma uygulamaları olan görünüm denetleyicimiz için kullandığımız alanları tanımlıyoruz.

  • m_lookInUse , görünüm denetiminin kullanımda olup olmadığını gösterir.
  • m_lookPointerID geçerli görünüm işaretçisinin benzersiz kimliğidir. İşaretçi kimliği değerini denetlediğimizde, görünüm işaretçisi ile taşıma işaretçisi arasında ayrım yapmak için bunu kullanırız.
  • m_lookLastPoint , sahne koordinatlarında, önceki karede yakalanan son noktadır.
  • m_lookLastDelta , geçerli m_position ile m_lookLastPoint arasındaki hesaplanan farktır.

Son olarak, 6 hareket derecesi için 6 Boole değeri tanımladık ve bu değerleri her yönlü taşıma eyleminin geçerli durumunu belirtmek için kullanırız (açık veya kapalı):

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

Denetleyicilerimizin durumunu güncelleştirmek için kullandığımız giriş verilerini yakalamak için 6 olay işleyicisini kullanırız:

  • OnPointerPressed. Oyuncu oyun ekranımızda işaretçiyle sol fare düğmesine bastı veya ekrana dokundu.
  • onPointerMoved. Oyuncu fareyi oyun ekranımızda işaretçiyle hareket ettirdi veya dokunmatik işaretçiyi ekrana sürükledi.
  • OnPointerReleased. Oyuncu oyun ekranımızda işaretçiyi içeren sol fare düğmesini serbest bıraktı veya ekrana dokunmayı durdurdu.
  • OnKeyDown. Oyuncu bir tuşa bastı.
  • OnKeyUp. Oyuncu bir anahtar yayınladı.

Son olarak, denetleyicilerin durum bilgilerini başlatmak, bunlara erişmek ve bunları güncelleştirmek için bu yöntemleri ve özellikleri kullanırız.

  • başlat. Uygulamamız denetimleri başlatmak ve bunları görüntü penceremizi açıklayan CoreWindow nesnesine eklemek için bu olay işleyicisini çağırır.
  • SetPosition. Uygulamamız, sahne alanında denetimlerimizin (x, y ve z) koordinatlarını ayarlamak için bu yöntemi çağırır.
  • SetOrientation. Uygulamamız bu yöntemi çağırarak kameranın eğim ve yanal açısını ayarlar.
  • get_Position. Uygulamamız, sahne alanında kameranın geçerli konumunu almak için bu özelliğe erişir. Geçerli kamera konumunu uygulamaya iletme yöntemi olarak bu özelliği kullanırsınız.
  • get_LookPoint. Uygulamamız, denetleyici kamerasının karşı karşıya olduğu geçerli noktayı almak için bu özelliğe erişir.
  • Güncelleme. Hareket ve görünüm denetleyicilerinin durumunu okur ve kamera konumunu güncelleştirir. Kamera denetleyicisi verilerini ve sahne alanında kamera konumunu yenilemek için uygulamanın ana döngüsünden bu yöntemi sürekli olarak çağırırsınız.

Şimdi, hareket-bakış kontrollerini uygulamak için ihtiyacınız olan tüm bileşenler burada. Şimdi bu parçaları birbirine bağlayalım.

Temel giriş olaylarını oluşturma

Windows Çalışma Zamanı olay dağıtıcısı , MoveLookController sınıfının örneklerinin işlemesini istediğimiz 5 olay sağlar:

Bu olaylar CoreWindow türünde uygulanır. Çalışabileceğiniz bir CoreWindow nesneniz olduğunu varsayıyoruz. Eğer nasıl edineceğinizi bilmiyorsanız, Evrensel Windows Platformu (UWP) C++ uygulamanızı DirectX görünümünü gösterecek şekilde ayarlama bölümüne bkz..

Bu olaylar uygulamamız çalışırken tetiklendiğinden, işleyiciler özel alanlarımızda tanımlanan denetleyicilerin durum bilgilerini güncelleştirir.

İlk olarak, fare ve dokunma işaretçisi olay işleyicilerini dolduralım. İlk olay işleyicisi olan OnPointerPressed() içinde, kullanıcı fareye tıkladığında veya görünüm denetleyicisi bölgesinde ekrana dokunduğunda ekranımızı yöneten CoreWindow'dan işaretçinin x-y koordinatlarını elde ederiz.

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

Bu olay işleyicisi, işaretçinin fare olup olmadığını (hem fareyi hem dokunmayı destekleyen bu örnek için) ve taşıma denetleyicisi alanında olup olmadığını denetler. Her iki ölçüt de doğruysa, işaretçiye yalnızca yeni bir basış olup olmadığını, özellikle de bu tıklamanın önceki bir hareket veya bakış girdisiyle ilişkisiz olup olmadığını kontrol eder ve m_moveInUse yanlış mı diye test eder. Bu durumda, işleyici, hareket kontrolcüsü alanında basmanın gerçekleştiği noktayı yakalar ve m_moveInUse true olarak ayarlar, böylece bu işleyici tekrar çağrıldığında hareket kontrolcüsü giriş etkileşiminin başlangıç konumu üzerine yazmaz. Ayrıca taşıma denetleyicisi işaretçi kimliğini geçerli işaretçinin kimliğine güncelleştirir.

İşaretçi fareyse veya dokunma işaretçisi hareket denetleyicisi alanında değilse, görünüm denetleyicisi alanında olmalıdır. m_lookLastPoint kullanıcının fare düğmesine bastığı veya dokunup basıldığı geçerli konuma ayarlar, deltayı sıfırlar ve görünüm denetleyicisinin işaretçi kimliğini geçerli işaretçi kimliğine güncelleştirir. Ayrıca, görünüm denetleyicisinin durumunu etkin olarak ayarlar.

İşaretçi Taşındı

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

İşaretçi her hareket ettiğinde OnPointerMoved olay işleyicisi tetiklenir (bu durumda, dokunmatik ekran işaretçisi sürükleniyorsa veya sol düğmeye basıldığında fare işaretçisi taşınıyorsa). İşaretçi kimliği, taşıma denetleyicisi işaretçisinin kimliğiyle aynıysa, taşıma işaretçisidir; aksi takdirde, etkin işaretçinin görünüm denetleyicisi olup olmadığını denetleriz.

Taşıma denetleyicisiyse yalnızca işaretçi konumunu güncelliyoruz. PointerMoved olayı tetiklenmeye devam ettiği sürece güncelleştirmeye devam ediyoruz çünkü son konumu, yakaladığımız ilk konumla OnPointerPressed olay işleyicisi ile karşılaştırmak istiyoruz.

Eğer görünüş denetleyicisiyse, işler biraz daha karmaşıktır. Yeni bir görünüm noktası hesaplamamız ve kamerayı onun üzerinde ortalamamız gerekir, bu nedenle son bakış noktası ile geçerli ekran konumu arasındaki deltayı hesaplayacağız ve ardından ölçek faktörümüzle çarparak görünüm hareketlerini ekran hareketinin mesafesine göre daha küçük veya daha büyük hale getirmek için ince ayar yapmalıyız. Bu değeri kullanarak, eğimi ve esneyi hesaplarız.

Son olarak, oyuncu fareyi hareket ettirmeyi veya ekrana dokunmayı bıraktığında, hareket etme veya bakış kontrolcüsü davranışlarını devre dışı bırakmamız gerekir. PointerReleased tetiklendiğinde çağırdığımız OnPointerReleased, m_moveInUse veya m_lookInUse'u FALSE olarak ayarlamak, kamera kaydırma hareketini kapatmak ve işaretçi kimliğini sıfırlamak için kullanılır.

PointerSerbestBırakıldı

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

Şimdiye kadar tüm dokunmatik ekran olaylarını işledik. Şimdi klavye tabanlı taşıma denetleyicisi için tuş giriş olaylarını işleyelim.

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

Bu tuşlardan birine basıldığında, bu olay işleyicisi ilgili yön taşıma durumunu true olarak ayarlar.

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

Anahtar serbest bırakıldığında, bu olay işleyicisi anahtarı false olarak ayarlar. Updateçağrısı yaptığımızda, bu hareket yönü durumlarını denetler ve kamerayı buna göre hareket ettirir. Bu, dokunma uygulamasından biraz daha basit!

Dokunma denetimlerini ve denetleyici durumunu başlatma

Şimdi olayları birbirine bağlayalım ve denetleyici durumunun tüm alanlarını başlatalım.

Başlat

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, uygulamanın CoreWindow örneğine bir parametre olarak başvuru alır ve geliştirdiğimiz olay işleyicilerini ilgili CoreWindowüzerinde uygun olaylara kaydeder. Taşıma ve görünüm işaretçisinin kimliklerini başlatır, dokunmatik ekran taşıma denetleyicisi uygulamamız için komut vektörunu sıfır olarak ayarlar ve uygulama başlatıldığında kamerayı doğrudan ileriye bakar şekilde ayarlar.

Kameranın konumunu ve yönünü alma ve ayarlama

Şimdi kameranın görünüm penceresine göre konumunu almak ve ayarlamak için bazı yöntemler tanımlayalım.

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

Denetleyici durum bilgilerini güncelleştirme

Şimdi, m_movePointerPosition ile izlenen işaretçi koordinat bilgilerini, dünya koordinat sistemimize göre yeni koordinat bilgilerine dönüştüren hesaplamalarımızı yapıyoruz. Ana uygulama döngüsünü her yenilediğimizde uygulamamız bu yöntemi çağırır. Bu nedenle, görünüm penceresine yansıtmadan önce görünüm matrisini güncelleştirmek için uygulamaya geçirmek istediğimiz yeni görünüm noktası konum bilgilerini hesaplayacağız.

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

}

Oyuncu dokunmatik tabanlı hareket denetleyicimizi kullandığında hareketli hareket istemediğimizden, işaretçinin çevresinde 32 piksel çapında bir sanal ölü bölge ayarladık. Ayrıca, komut değeri artı bir hareket kazanç oranı olan hızı da ekleriz. (İşaretçinin hareket denetleyicisi alanında hareket mesafesine göre hareket hızını yavaşlatmak veya hızlandırmak için bu davranışı istediğiniz gibi ayarlayabilirsiniz.)

Hızı hesaplarken, hareket ve bakış denetleyicilerinden alınan koordinatları, sahne için görünüm matrisimizi hesaplayan yönteme gönderdiğimiz gerçek bakış noktasının hareketine dönüştürmek amacıyla çeviririz. İlk olarak, x koordinatını ters çeviririz, çünkü görüş denetleyicisiyle tıkladığımızda ya da sağa veya sola çektiğimizde, kamera merkezi ekseninde sallanıyormuş gibi sahnede görünüm noktası zıt yöne dönmesine neden olur. Ardından y ve z eksenlerini değiştiririz çünkü hareket denetleyicisindeki yukarı/aşağı tuşa basma veya dokunma sürükleme hareketi (y ekseni davranışı olarak okuma) görünüm noktasını ekranın içine veya dışına (z ekseni) taşıyan bir kamera eylemine çevrilmelidir.

Oyuncunun bakış noktasının son konumu, hesaplanan hızın yanı sıra son konumdur ve işleyici get_Position yöntemini çağırdığında (büyük olasılıkla her kare için kurulum sırasında) işleyici tarafından okunan konumdur. Bundan sonra move komutunu sıfırlayacağız.

Görünüm matrisini yeni kamera konumuyla güncelleştirme

Kameramızın odaklandığı ve uygulamanıza bunu her istediğinizde güncelleştirilen bir sahne alanı koordinatı elde edebiliriz (örneğin, ana uygulama döngüsünde 60 saniyede bir). Bu sahte kod, uygulayabileceğiniz çağırma davranışını önerir:

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

Tebrikler! Oyununuzda hem dokunmatik ekranlar için hem de klavye/fare girişi için temel hareket etme ve bakış kontrolleri uyguladınız!