Windows Dev Center

Esercitazione: aggiungere controlli di tocco al gioco DirectX

In questa esercitazione imparerai ad aggiungere controlli di tocco di base al tuo gioco C++ per lo Store con DirectX. Ti mostreremo come aggiungere controlli basati su tocco per muovere una videocamera fissa su piano in un ambiente Direct3D, dove il trascinamento con un dito o uno stilo cambia la prospettiva della videocamera.

Puoi incorporare questi controlli in giochi in cui vuoi che il giocatore usi il trascinamento per scorrere o fare una panoramica su un ambiente 3D, come una mappa o un campo da gioco. Ad esempio, in un gioco di strategia o un puzzle, puoi usare questi controlli per consentire al giocatore di visualizzare un ambiente di gioco più grande dello schermo facendo una panoramica a destra o a sinistra.

Nota  Il nostro codice funziona anche con i controlli di panoramica basati su mouse. Gli eventi correlati al puntatore sono astrazioni delle API Windows Runtime, quindi possono gestire sia gli eventi puntatore basati su tocco che basati su mouse.

Obiettivi

  • Creare un semplice controllo di trascinamento tramite tocco per pianificare una videocamera su piano fisso in un gioco DirectX.

Configurazione dell'infrastruttura di base degli eventi di tocco

Per iniziare, definiamo il nostro tipo di controller di base CameraPanController, in questo caso. In questa esercitazione definiamo un controller come un'idea astratta, l'insieme dei comportamenti consentiti all'utente.

La classe CameraPanController è una raccolta di informazioni regolarmente aggiornate sullo stato del controller della videocamera e offre alla nostra app un modo per ottenere queste informazioni dal proprio ciclo di aggiornamento.


using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;

// Methods to get input from the UI pointers
ref class CameraPanController
{
}

Creiamo ora un'intestazione che definisca lo stato del controller della videocamera, oltre ai metodi e ai gestori eventi di base che implementano le interazioni del controller stesso.


ref class CameraPanController
{
private:
    // properties of the controller object
    float3 m_position;			    // the position of the camera

    // properties of the camera pan control
    bool m_panInUse;			    
    uint32 m_panPointerID;		    
    float2 m_panFirstDown;		    
    float2 m_panPointerPosition;   
    float3 m_panCommand;		    

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

    // accessor to set the position of the ontroller
    void SetPosition( _In_ float3 pos );

	   // accessor to set fixed "look point" of the controller
	   float3 get_FixedLookPoint();

    // returns the position of the controller object
    float3 get_Position();


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

};  // class CameraPanController

I campi privati contengono lo stato corrente del controller della videocamera. Vediamoli in dettaglio.

  • m_position è la posizione della videocamera nello spazio della scena. In questo esempio il valore della coordinata z è fisso su 0. Potremmo usare un float2 per rappresentare questo valore, ma ai fini dell'esempio e per l'estendibilità futura useremo un float3. Passiamo il valore tramite la proprietà get_Position all'app stessa, in modo che possa aggiornare il riquadro di visualizzazione di conseguenza.
  • m_panInUse è un valore booleano che indica se è attiva un'operazione di panoramica o, più precisamente, se il giocatore sta toccando lo schermo e muovendo la videocamera.
  • m_panPointerID è un ID univoco per il puntatore. Non lo useremo nell'esempio, ma è buona pratica associare la classe di stato del controller a un puntatore specifico.
  • m_panFirstDown è il primo punto dello schermo che il giocatore ha toccato o in cui ha fatto clic con il mouse durante l'operazione di panoramica della videocamera. Useremo questo valore in seguito per impostare una zona morta in modo da impedire qualsiasi tremolio quando lo schermo viene toccato o se il mouse viene scosso leggermente.
  • m_panPointerPosition è il punto dello schermo in cui il giocatore ha attualmente spostato il puntatore. Viene usato per determinare la direzione in cui il giocatore voleva spostarsi mediante un confronto con m_panFirstDown.
  • m_panCommand è il comando calcolato finale per il controller della videocamera: in su, in giù, a sinistra o a destra. Poiché stiamo usando una videocamera fissa sul piano x-y, questo potrebbe essere un valore float2.

Usiamo questi tre gestori eventi per aggiornare le informazioni sullo stato del controller della videocamera.

  • OnPointerPressed è un gestore eventi che viene chiamato dall'app quando il giocatore preme un dito sulla superficie di tocco e il puntatore si sposta sulle coordinate del punto di pressione.
  • OnPointerMoved è un gestore eventi che viene chiamato dall'app quando il giocatore passa un dito sulla superficie di tocco. Viene aggiornato con le nuove coordinate del percorso di trascinamento.
  • OnPointerReleased è un gestore eventi che viene chiamato dall'app quando il giocatore solleva il dito dalla superficie di tocco.

Infine, usiamo questi metodi e queste proprietà per inizializzare, accedere e aggiornare le informazioni sullo stato del controller della videocamera.

  • Initialize è un gestore eventi che viene chiamato dall'app per inizializzare i controlli e associarli all'oggetto CoreWindow che descrive la finestra di visualizzazione.
  • SetPosition è un metodo che viene chiamato dall'app per impostare le coordinate (x, y e z) dei nostri controlli nello spazio della scena. Tieni presente che la nostra coordinata z è 0 per tutta la durata dell'esercitazione.
  • get_Position è una proprietà a cui l'app accede per ottenere la posizione corrente della videocamera nello spazio della scena. Devi usare questa proprietà per comunicare all'app la posizione corrente della videocamera.
  • get_FixedLookPoint è una proprietà a cui l'app accede per ottenere il punto corrente inquadrato dalla videocamera. In questo esempio la videocamera è bloccata perpendicolarmente al piano x-y.
  • Update è un metodo che legge lo stato del controller e aggiorna la posizione della videocamera. Devi chiamare continuamente questo metodo dal ciclo principale dell'app per aggiornare i dati del controller della videocamera e la posizione della videocamera nello spazio della scena.

Ora hai tutti i componenti che ti servono per implementare i controlli di tocco. Puoi individuare il punto e il momento in cui si sono verificati eventi puntatore tramite tocco o mouse e la relativa azione. Puoi impostare la posizione e l'orientamento della videocamera in relazione allo spazio della scena e tenere traccia delle modifiche. Infine, puoi comunicare la nuova posizione della videocamera all'app chiamante.

Ora non ci resta che mettere insieme i pezzi.

Creazione degli eventi di tocco di base

Il dispatcher eventi di Windows Runtime offre 3 eventi che devono essere gestiti dalla nostra app:

Questi eventi vengono implementati nel tipo CoreWindow. Partiamo dal presupposto che sia presente un oggetto CoreWindow da usare. Per saperne di più, vedi Come impostare l'app C++ di Windows Store per la visualizzazione di una vista DirectX.

Poiché questi eventi vengono generati mentre l'app è in esecuzione, i gestori aggiornano le informazioni sullo stato del controller della videocamera definite nei campi privati.

Iniziamo subito popolando i gestori eventi del puntatore tocco. Nel primo gestore eventi, OnPointerPressed, otteniamo le coordinate x-y del puntatore dall'oggetto CoreWindow che gestisce la visualizzazione quando il giocatore tocca lo schermo o fa clic con il mouse.

OnPointerPressed


void CameraPanController::OnPointerPressed(
                                           _In_ CoreWindow^ sender,
                                           _In_ PointerEventArgs^ args)
{
    // get the current pointer position
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( 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 location of initial contact
       m_panPointerPosition = position;
       m_panPointerID = pointerID;				// store the id of pointer using this control
       m_panInUse = TRUE;
    }
    
}


Usiamo questo gestore per comunicare all'istanza corrente di CameraPanController che il controller della videocamera deve essere considerato attivo impostando m_panInUse su TRUE. In questo modo, quando l'app chiama Update, userà i dati della posizione corrente per aggiornare il riquadro di visualizzazione.

Ora che abbiamo stabilito i valori base per il movimento della videocamera quando l'utente tocca lo schermo oppure fa clic o preme nella finestra di visualizzazione, dobbiamo determinare cosa fare quando l'utente trascina il dito o lo stilo sullo schermo o muove il mouse con un pulsante premuto.

Il gestore dell'evento OnPointerMoved viene generato ad ogni movimento del puntatore, ad ogni istante in cui il giocatore lo trascina sullo schermo. Dobbiamo comunicare costantemente all'app la posizione corrente del puntatore, e lo facciamo in questo modo.

OnPointerMoved


void CameraPanController::OnPointerMoved(
                                        _In_ CoreWindow ^sender,
                                        _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    m_panPointerPosition = position;
}

Infine, dobbiamo disattivare la panoramica della videocamera quando il giocatore smette di toccare lo schermo. Usiamo OnPointerReleased, che viene chiamato quando viene generato l'evento PointerReleased, per impostare m_panInUse su FALSE e per disattivare la panoramica della videocamera e azzerare l'ID del puntatore.

OnPointerReleased


void CameraPanController::OnPointerReleased(
                                             _In_ CoreWindow ^sender,
                                             _In_ PointerEventArgs ^args)
{
    uint32 pointerID = args->CurrentPoint->PointerId;
    float2 position = float2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    m_panInUse = FALSE;
    m_panPointerID = 0;
}

Inizializzazione dei controlli di tocco e dello stato del controller

È giunto il momento di associare gli eventi e inizializzare tutti i campi di stato di base del controller della videocamera.

Initialize


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

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

    //	Initialize this as it is reset every frame
    m_panCommand = float3( 0.0f, 0.0f, 0.0f );

}

Initialize accetta un riferimento all'istanza CoreWindow dell'app come parametro e registra i gestori di eventi sviluppati negli eventi appropriati in tale oggetto CoreWindow.

Recupero e impostazione della posizione del controller della videocamera

Definiamo ora alcuni metodi per ottenere e impostare la posizione del controller della videocamera nello spazio della scena.


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

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

float3 CameraPanController::get_FixedLookPoint()
{
    // For this sample, we don't need to use the trig functions because our
    // look point is fixed. 
    return m_position + float3( 0, 0, 1 );
}

SetPosition è un metodo pubblico che viene chiamato dall'app per impostare la posizione del controller della videocamera su un punto specifico.

get_Position è la proprietà pubblica più importante: è il modo in cui l'app ottiene la posizione corrente del controller della videocamera nello spazio della scena in modo da poter aggiornare il riquadro di visualizzazione di conseguenza.

get_FixedLookPoint è una proprietà pubblica che, in questo esempio, ottiene un punto di visuale perpendicolare al piano x-y. Puoi modificare questo metodo in modo da usare le funzioni trigonometriche, seno e coseno, per calcolare i valori delle coordinate x, y e z nel caso tu voglia creare più angoli obliqui per la videocamera fissa.

Aggiornamento delle informazioni di stato del controller della videocamera

Eseguiamo ora alcuni calcoli per convertire le informazioni sulle coordinate del puntatore registrate in m_panPointerPosition in nuove informazioni sulle coordinate relativamente alo spazio della scena 3D. L'app chiama in genere questo metodo ogni volta che aggiorniamo il ciclo principale dell'app e in esso calcoliamo le informazioni sulla nuova posizione che vogliamo passare all'app per aggiornare la matrice di vista prima della proiezione nel riquadro di visualizzazione.




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

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

	   float3 command = m_panCommand;
   
    // our velocity is based on the command
    float3 Velocity;
    Velocity.x =  command.x;
    Velocity.y =  command.y;
    Velocity.z =  0.0f;

    // integrate
    m_position = m_position + Velocity;

    // Clear the movement input accumulator for use during next frame
    m_panCommand = float3( 0.0f, 0.0f, 0.0f );

}

Poiché vogliano evitare qualsiasi tremolio causato da un tocco o dal movimento del mouse durante la panoramica della videocamera, impostiamo una zona morta attorno al puntatore con un diametro di 32 pixel. Abbiamo anche un valore per la velocità, che in questo caso è 1:1 con l'attraversamento in pixel del puntatore oltre la zona morta. Puoi modificare questo comportamento a tuo piacimento, rallentando o velocizzando il movimento.

Aggiornamento della matrice della vista in base alla nuova posizione della videocamera

Possiamo ora ottenere le coordinate dello spazio di scena inquadrato dalla videocamera, che vengono aggiornate ogni volta in cui istruisci l'app in tal senso (ad esempio, ogni 60 secondi nel ciclo principale dell'app). Questo pseudocodice suggerisce il comportamento chiamante da implementare:


 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
        float3( 0, 1, 0 )					// the axis that is "up" in our space
        );	

Ecco fatto. Hai implementato un semplice set di controlli di tocco per la panoramica della videocamera in un'app di Windows Store basata su DirectX con C++

 

 

Mostra:
© 2015 Microsoft