Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Scopri come aggiungere controlli tradizionali di spostamento del mouse e della tastiera (noti anche come controlli mouselook) al tuo gioco DirectX.
Viene inoltre illustrato il supporto per il movimento e la visuale sui dispositivi touch, con il controller del movimento definito come la sezione inferiore sinistra dello schermo che si comporta come un input direzionale e il controller della visuale definito per il resto dello schermo, con la fotocamera che si centra sull'ultimo punto in cui il giocatore ha toccato in quell'area.
Se questo concetto di controllo ti è sconosciuto, pensala in questo modo: la tastiera (o i comandi direzionali basati sul tocco) controllano le tue gambe in questo spazio 3D e si comportano come se le gambe fossero capaci solo di muoversi in avanti, indietro o lateralmente a sinistra e a destra. Il mouse (o il puntatore tattile) controlla la tua testa. Si usa la testa per guardare in direzione - sinistra o destra, su o giù, o da qualche parte in quell'aereo. Se c'è una destinazione nella visualizzazione, si userà il mouse per centrare la visualizzazione della fotocamera su tale destinazione, quindi premere il tasto avanti per spostarsi verso di esso o tornare indietro per allontanarsi da esso. Per cerchiare il bersaglio, mantieni la visualizzazione della fotocamera centrata sul bersaglio e sposta contemporaneamente a sinistra o a destra. Puoi vedere come si tratta di un metodo di controllo molto efficace per esplorare gli ambienti 3D!
Questi controlli sono comunemente noti come controlli WASD nei giochi, in cui i tasti W, A, S e D vengono usati per lo spostamento fisso della fotocamera del piano x-z e il mouse viene usato per controllare la rotazione della fotocamera intorno agli assi x e y.
Obiettivi
- Aggiungi controlli di base di movimento al tuo gioco DirectX sia per il mouse che per la tastiera e per i touch screen.
- Implementare una fotocamera di prima persona usata per spostarsi in un ambiente 3D.
Nota sulle implementazioni del controllo tocco
Per i controlli touch, implementiamo due controller: il controller di spostamento, che gestisce il movimento nel piano x-z rispetto al punto di vista della fotocamera; e il controller di visuale, che orienta il punto di vista della fotocamera. Il controller di movimento mappa ai pulsanti WASD della tastiera e il controller di visuale mappa al mouse. Per i controlli touch, tuttavia, è necessario definire un'area dello schermo che funge da input direzionale o da pulsanti WASD virtuali, mentre il resto dello schermo serve come spazio di input per i controlli di visualizzazione.
La schermata è simile alla seguente.
layout del controller di spostamento
Quando si sposta il puntatore touch nell'angolo in basso a sinistra dello schermo, un movimento verso l'alto farà avanzare la fotocamera. Qualsiasi movimento verso il basso farà sì che la fotocamera si sposti all'indietro. Lo stesso vale per il movimento sinistro e destro all'interno dello spazio puntatore del controller di spostamento. Al di fuori di questo spazio, diventa un controller di visuale -- basta toccare o trascinare la fotocamera dove vuoi puntarla.
Configurare l'infrastruttura di base per gli eventi di input
Prima di tutto, è necessario creare la classe di controllo usata per gestire gli eventi di input dal mouse e dalla tastiera e aggiornare la prospettiva della fotocamera in base a tale input. Poiché stiamo implementando controlli di movimento e visuale, lo chiamiamo 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
A questo punto, creiamo un header che definisce lo stato del controllore movimento-sguardo e della fotocamera in prima persona, oltre ai metodi di base e ai gestori eventi che implementano i controlli e che aggiornano lo stato della fotocamera.
#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
Il codice contiene 4 gruppi di campi privati. Esaminiamo lo scopo di ognuno di essi.
Prima di tutto, definiamo alcuni campi utili che contengono le informazioni aggiornate sulla visualizzazione della fotocamera.
- m_position è la posizione della fotocamera (e quindi il viewplane) nella scena 3D, usando le coordinate della scena.
- m_pitch è l'inclinazione della fotocamera, o la sua rotazione su e giù intorno all'asse x del piano di vista, in radianti.
- m_yaw è l'imbardamento della fotocamera, o la rotazione da sinistra a destra intorno all'asse y del viewplane, in radianti.
Definire ora i campi usati per archiviare informazioni sullo stato e sulla posizione dei controller. Prima di tutto, definiamo i campi necessari per il controller di spostamento basato sul tocco. (Non c'è niente di speciale necessario per l'implementazione della tastiera del controller di spostamento. È sufficiente leggere gli eventi della tastiera con gestori specifici.
- m_moveInUse indica se il controller di spostamento è in uso.
- m_movePointerID è l'ID univoco per il puntatore di movimento corrente. Lo usiamo per distinguere tra il puntatore visivo e il puntatore di movimento quando controlliamo il valore ID del puntatore.
- m_moveFirstDown è il punto sullo schermo in cui il giocatore ha toccato prima l'area del puntatore del controller di movimento. Questo valore verrà usato poi per impostare una zona morta per evitare che i piccoli movimenti rendano instabile l'inquadratura.
- m_movePointerPosition è il punto sullo schermo in cui il giocatore ha attualmente spostato il puntatore. Lo usiamo per determinare la direzione in cui il giocatore voleva spostarsi esaminandolo rispetto a m_moveFirstDown.
- m_moveCommand è il comando calcolato finale per il controller di spostamento: su (avanti), giù (indietro), a sinistra o a destra.
Ora definiamo i campi che usiamo per il nostro controller visivo, sia per le implementazioni del mouse sia per quelle del tocco.
- m_lookInUse indica se il controllo look è in uso.
- m_lookPointerID è l'ID univoco per il puntatore di ricerca corrente. Lo usiamo per distinguere tra il puntatore visivo e il puntatore di movimento quando controlliamo il valore ID del puntatore.
- m_lookLastPoint è l'ultimo punto nelle coordinate della scena che è stato acquisito nel fotogramma precedente.
- m_lookLastDelta è la differenza calcolata tra la m_position corrente e m_lookLastPoint.
Infine, definiamo 6 valori booleani per i 6 gradi di movimento, che usiamo per indicare lo stato corrente di ogni azione di spostamento direzionale (on o off):
- m_forward, m_back, m_left, m_right, m_up e m_down.
Usiamo i 6 gestori eventi per acquisire i dati di input usati per aggiornare lo stato dei controller:
- OnPointerPressed. Il giocatore ha premuto il pulsante sinistro del mouse con il puntatore nella schermata del gioco o ha toccato lo schermo.
- OnPointerMoved. Il giocatore ha spostato il puntatore con il mouse nella schermata del nostro gioco, o ha trascinato il puntatore tattile sullo schermo.
- OnPointerReleased. Il giocatore ha rilasciato il pulsante sinistro del mouse mentre il puntatore era sulla schermata del nostro gioco, oppure ha smesso di toccare lo schermo.
- OnKeyDown. Il giocatore ha premuto un tasto.
- OnKeyUp. Il giocatore ha rilasciato una chiave.
Infine, usiamo questi metodi e proprietà per inizializzare, accedere e aggiornare le informazioni sullo stato dei controller.
- Inizializzare. L'app chiama questo gestore eventi per inizializzare i controlli e collegarli all'oggetto CoreWindow che descrive la finestra di visualizzazione.
- SetPosition. L'app chiama questo metodo per impostare le coordinate (x, y e z) dei controlli nello spazio della scena.
- ImpostaOrientamento. L'app chiama questo metodo per impostare l'inclinazione e l'imbardata della fotocamera.
- get_Position. L'app accede a questa proprietà per ottenere la posizione corrente della fotocamera nello spazio della scena. Questa proprietà viene usata come metodo per comunicare la posizione corrente della fotocamera all'app.
- get_LookPoint. L'app accede a questa proprietà per ottenere il punto corrente verso cui è orientata la fotocamera del controller.
- Aggiornamento. Legge lo stato dei controller di movimento e visuale e aggiorna la posizione della fotocamera. Chiami continuamente questo metodo dal ciclo principale dell'applicazione per aggiornare i dati del controllo della fotocamera e la posizione della fotocamera nello spazio della scena.
A questo punto, hai tutti i componenti necessari per implementare i tuoi controlli di spostamento. Quindi, connettiamo questi pezzi insieme.
Creare gli eventi di input di base
Il gestore di eventi di Windows Runtime fornisce 5 eventi che le istanze della classe MoveLookController devono gestire:
Questi eventi vengono implementati nel tipo di CoreWindow. Si presuppone che si disponga di un oggetto CoreWindow con cui lavorare. Se non sai come ottenerlo, vedi Come configurare la tua app UWP (Universal Windows Platform) C++ per visualizzare una visualizzazione DirectX.
Man mano che questi eventi vengono generati mentre la nostra app è in esecuzione, i gestori degli eventi aggiornano le informazioni sullo stato dei controller definite nei nostri campi privati.
Prima di tutto, implementiamo i gestori degli eventi per il mouse e per il puntatore touch. Nel primo gestore eventi, OnPointerPressed(), otteniamo le coordinate x-y del puntatore dal CoreWindow che gestisce la visualizzazione quando l'utente clicca con il mouse o tocca lo schermo nell'area del controller di visualizzazione.
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;
}
}
}
Questo gestore eventi controlla se il puntatore non è il mouse (ai fini di questo esempio, che supporta sia il mouse che il tocco) e se si trova nell'area del controller di spostamento. Se entrambi i criteri sono veri, verifica se il puntatore è appena stato premuto, in particolare se questo clic non è correlato a uno spostamento o a un input di visualizzazione precedente, verificando se m_moveInUse è falso. In tal caso, il gestore acquisisce il punto nell'area del controller di spostamento in cui è avvenuta la pressione e imposta m_moveInUse su true, in modo che quando questo gestore viene chiamato di nuovo, non sovrascriverà la posizione iniziale dell'interazione di input del controller di spostamento. Aggiorna anche l'ID del puntatore del controller di spostamento all'ID del puntatore corrente.
Se il puntatore è il mouse o se il puntatore tattile non si trova nell'area del controller di spostamento, deve trovarsi nell'area del controller di visualizzazione. Imposta m_lookLastPoint sulla posizione corrente in cui l'utente ha premuto un pulsante del mouse o toccato lo schermo e tenuto premuto, reimposta il delta e aggiorna l'ID puntatore del controller di visualizzazione all'ID puntatore corrente. Imposta anche lo stato del look controller su attivo.
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);
}
}
Il OnPointerMoved gestore eventi viene attivato ogni volta che il puntatore si sposta (in questo caso, se viene trascinato un puntatore dello schermo tattile o se il puntatore del mouse viene spostato quando viene premuto il pulsante sinistro). Se l'ID del puntatore è uguale all'ID del puntatore del controller di movimento, allora è il puntatore di movimento; altrimenti, verifichiamo se è il controller di visualizzazione a essere il puntatore attivo.
Se si tratta del controller di spostamento, è sufficiente aggiornare la posizione del puntatore. Continuiamo ad aggiornarlo finché l'evento PointerMoved continua a essere attivato, perché vogliamo confrontare la posizione finale con la prima posizione che abbiamo catturato con il gestore eventi OnPointerPressed.
Se è il controller dell'aspetto, le cose sono un po' più complicate. Dobbiamo calcolare un nuovo punto di osservazione e centrare la fotocamera su di esso, quindi calcoliamo il delta tra l'ultimo punto di osservazione e la posizione attuale dello schermo, e poi moltiplichiamo per il fattore di scala, che possiamo modificare per rendere i movimenti di osservazione più piccoli o più grandi in relazione alla distanza dello spostamento dello schermo. Usando tale valore, calcoliamo la inclinazione e l'imbardata.
Infine, è necessario disattivare i comportamenti del controller di spostamento o di aspetto quando il giocatore smette di spostare il mouse o toccare lo schermo. Usiamo OnPointerReleased, che chiamiamo quando si attiva PointerReleased, per impostare m_moveInUse o m_lookInUse su FALSE, disattivare lo spostamento della panoramica della fotocamera e azzerare l'ID puntatore.
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;
}
}
Finora abbiamo gestito tutti gli eventi touch screen. A questo punto, gestiamo gli eventi chiave di input per un controller di spostamento basato su tastiera.
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;
}
Finché si preme uno di questi tasti, questo gestore eventi imposta lo stato di spostamento direzionale corrispondente su 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;
}
E quando il tasto viene rilasciato, questo gestore eventi lo imposta su false. Quando chiamiamo Update, controlla questi stati di spostamento direzionali e sposta la fotocamera di conseguenza. Questo è un po' più semplice dell'implementazione touch!
Inizializzare i controlli tattili e lo stato del controller
Colleghiamo ora gli eventi e inizializziamo tutti i campi dello stato del controller.
Inizializzare
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.
}
Inizializza accetta come parametro un riferimento all'istanza CoreWindow dell'app e registra i gestori degli eventi che abbiamo sviluppato agli eventi appropriati di tale CoreWindow. Inizializza gli ID del puntatore di movimento e di visuale, imposta il vettore di comando per l'implementazione del controller di movimento del touch screen su zero e imposta la fotocamera per guardare dritto davanti all'avvio dell'app.
Ottenere e impostare la posizione e l'orientamento della fotocamera
Definiamo alcuni metodi per ottenere e impostare la posizione della fotocamera rispetto al riquadro di visualizzazione.
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;
}
Aggiornamento delle informazioni sullo stato del controller
A questo punto, eseguiamo i calcoli che convertono le informazioni sulle coordinate del puntatore rilevate in m_movePointerPosition in nuove informazioni sulle coordinate del nostro sistema di coordinate mondiale. L'app chiama questo metodo ogni volta che aggiorniamo il ciclo principale dell'app. Quindi, è qui che calcoliamo le nuove informazioni sulla posizione del punto di vista che vogliamo passare all'app per aggiornare la matrice di visualizzazione prima della proiezione nel riquadro di visualizzazione.
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);
}
Poiché non vogliamo un movimento instabile quando il giocatore usa il controller di movimento basato sul tocco, impostiamo una zona morta virtuale intorno al puntatore con un diametro di 32 pixel. Aggiungiamo anche velocità, ovvero il valore del comando più un tasso di aumento del movimento. È possibile regolare questo comportamento in base alle proprie esigenze, per rallentare o velocizzare la velocità di movimento in base alla distanza in cui il puntatore si sposta nell'area del controller di spostamento.
Quando calcoliamo la velocità, traduciamo anche le coordinate ricevute dai controller di movimento e visuale nel movimento del punto di vista effettivo che inviamo al metodo che calcola la nostra matrice di visualizzazione per la scena. Per prima cosa, invertiamo la coordinata x, perché se si fa un clic-movimento o si trascina a sinistra o a destra con il controller di visualizzazione, il punto di vista ruota nella direzione opposta nella scena, proprio come farebbe una fotocamera oscillando attorno al proprio asse centrale. Quindi, scambiamo gli assi y e z, perché la pressione di un tasto su/giù o il trascinamento tramite tocco (letto come comportamento sull'asse y) sul controller di spostamento deve tradursi in un'azione della fotocamera che sposta il punto di vista all'interno o all'esterno dello schermo (asse z).
La posizione finale del punto di riferimento visivo per l'utente è la somma dell'ultima posizione e della velocità calcolata, e questo è ciò che viene letto dal renderer quando chiama il metodo get_Position (molto probabilmente durante la configurazione per ogni fotogramma). Successivamente, il comando di spostamento viene reimpostato su zero.
Aggiornamento della matrice di visualizzazione con la nuova posizione della fotocamera
È possibile ottenere una coordinata dello spazio della scena su cui si concentra la fotocamera e che viene aggiornata ogni volta che si indica all'app di farlo (ad esempio ogni 60 secondi nel ciclo principale dell'app). Questo pseudocodice suggerisce la modalità di chiamata che puoi implementare:
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
);
Congratulazioni! Hai implementato i controlli di base per il movimento e la visuale sia sui touch screen che per l'input da tastiera/mouse nel tuo gioco!