Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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.
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:
- İşaretçiBasılı
- İşaretçi Taşındı
- İşaretçiSerbestBırakıldı
- KeyUp
- KeyDown
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!