Compartir a través de


Controles táctiles para juegos

Aprende a agregar controles táctiles básicos a tu juego de C++ de Plataforma universal de Windows (UWP) con DirectX. Te mostramos cómo agregar controles táctiles para mover una cámara de plano fijo en un entorno de Direct3D, donde arrastrar con un dedo o lápiz desplaza la perspectiva de la cámara.

Puedes incorporar estos controles en juegos en los que quieres que el jugador arrastre para desplazarse o desplazarse por un entorno 3D, como un mapa o un campo de juego. Por ejemplo, en un juego de estrategia o rompecabezas, puedes usar estos controles para permitir que el jugador vea un entorno de juego que sea mayor que la pantalla al desplazarse hacia la izquierda o hacia la derecha.

Nota Nuestro código también funciona con controles de movimiento panorámico basados en el mouse. Las API de Windows Runtime abstraen los eventos relacionados con el puntero, por lo que pueden controlar eventos de puntero táctil o basado en mouse.

 

Objetivos

  • Crea un simple control de arrastre táctil para desplazar una cámara de plano fijo en un juego DirectX.

Configuración de la infraestructura básica de eventos táctiles

En primer lugar, definimos nuestro tipo de controlador básico, CameraPanController, en este caso. En este caso, definimos un controlador como una idea abstracta, el conjunto de comportamientos que el usuario puede realizar.

La clase CameraPanController es una colección actualizada periódicamente de información sobre el estado del controlador de cámara y proporciona una manera de que nuestra aplicación obtenga esa información de su bucle de actualización.

using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;
#include <directxmath.h>

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

Ahora, vamos a crear un encabezado que defina el estado del controlador de cámara y los métodos básicos y controladores de eventos que implementan las interacciones del controlador de cámara.

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

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

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

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

public:

    // Methods to get input from the UI pointers
    void OnPointerPressed(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnPointerMoved(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    void OnPointerReleased(
        _In_ Windows::UI::Core::CoreWindow^ sender,
        _In_ Windows::UI::Core::PointerEventArgs^ args
        );

    // Set up the Controls supported by this controller
    void Initialize( _In_ Windows::UI::Core::CoreWindow^ window );

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

};  // Class CameraPanController

Los campos privados contienen el estado actual del controlador de cámara. Vamos a revisarlos.

  • m_position es la posición de la cámara en el espacio de la escena. En este ejemplo, el valor de coordenada z se fija en 0. Podríamos usar directX::XMFLOAT2 para representar este valor, pero para los fines de esta muestra y extensibilidad futura, usamos un directX::XMFLOAT3. Pasamos este valor a través de la propiedad get_Position a la propia aplicación para que pueda actualizar la ventanilla en consecuencia.
  • m_panInUse es un valor booleano que indica si una operación de panorámica está activa; o, más concretamente, si el reproductor está tocando la pantalla y moviendo la cámara.
  • m_panPointerID es un identificador único para el puntero. No lo usaremos en el ejemplo, pero se recomienda asociar la clase de estado del controlador con un puntero específico.
  • m_panFirstDown es el punto en la pantalla donde el jugador tocó la pantalla por primera vez o ha clic en el mouse durante la acción de panorámica de la cámara. Usamos este valor más adelante para establecer una zona muerta para evitar la vibración cuando se toca la pantalla, o si el mouse se agita un poco.
  • m_panPointerPosition es el punto en la pantalla donde el jugador ha movido actualmente el puntero. Lo usamos para determinar la dirección que el jugador quería mover examinando con respecto a m_panFirstDown.
  • m_panCommand es el comando calculado final para el controlador de cámara: arriba, abajo, izquierda o derecha. Dado que estamos trabajando con una cámara fija en el plano x-y, esto podría ser un valor DirectX::XMFLOAT2 en su lugar.

Usamos estos 3 controladores de eventos para actualizar la información de estado del controlador de cámara.

  • OnPointerPressed es un controlador de eventos al que llama nuestra aplicación cuando los jugadores presionan un dedo en la superficie táctil y el puntero se mueve a las coordenadas de la prensa.
  • OnPointerMoved es un controlador de eventos al que la aplicación llama cuando el jugador desliza un dedo a través de la superficie táctil. Se actualiza con las nuevas coordenadas de la ruta de acceso de arrastre.
  • OnPointerReleased es un controlador de eventos al que llama la aplicación cuando el jugador quita el dedo presionado de la superficie táctil.

Por último, usamos estos métodos y propiedades para inicializar, acceder y actualizar la información de estado del controlador de cámara.

  • Initialize es un controlador de eventos al que la aplicación llama para inicializar los controles y adjuntarlos al objeto CoreWindow que describe la ventana de presentación.
  • SetPosition es un método que la aplicación llama a para establecer las coordenadas (x, y y z) de los controles en el espacio de la escena. Tenga en cuenta que nuestra coordenada z es 0 en este tutorial.
  • get_Position es una propiedad a la que accede nuestra aplicación para obtener la posición actual de la cámara en el espacio de la escena. Esta propiedad se usa como forma de comunicar la posición actual de la cámara a la aplicación.
  • get_FixedLookPoint es una propiedad a la que accede nuestra aplicación para obtener el punto actual hacia el que se enfrenta la cámara del controlador. En este ejemplo, se bloquea normalmente en el plano x-y.
  • Update es un método que lee el estado del controlador y actualiza la posición de la cámara. Llamas continuamente a esto <> desde el bucle principal de la aplicación para actualizar los datos del controlador de cámara y la posición de la cámara en el espacio de la escena.

Ahora, tiene aquí todos los componentes que necesita para implementar controles táctiles. Puede detectar cuándo y dónde se han producido los eventos de puntero táctil o del mouse y cuál es la acción. Puede establecer la posición y la orientación de la cámara en relación con el espacio de la escena y realizar un seguimiento de los cambios. Por último, puedes comunicar la nueva posición de la cámara a la aplicación que llama.

Ahora, vamos a conectar estas piezas.

Creación de los eventos táctiles básicos

El distribuidor de eventos de Windows Runtime proporciona tres eventos que queremos que nuestra aplicación controle:

Estos eventos se implementan en el tipo CoreWindow. Se supone que tiene un objeto CoreWindow con el que trabajar. Para obtener más información, consulta Cómo configurar tu aplicación de C++ para UWP para mostrar una vista directX.

A medida que se activan estos eventos mientras se ejecuta la aplicación, los controladores actualizan la información de estado del controlador de cámara definida en nuestros campos privados.

En primer lugar, vamos a rellenar los controladores de eventos del puntero táctil. En el primer controlador de eventos, OnPointerPressed, obtenemos las coordenadas x-y del puntero de CoreWindow que administra nuestra pantalla cuando el usuario toca la pantalla o hace clic en el mouse.

OnPointerPressed

void CameraPanController::OnPointerPressed(
                                           _In_ CoreWindow^ sender,
                                           _In_ PointerEventArgs^ args)
{
    // Get the current pointer position.
    uint32 pointerID = args->CurrentPoint->PointerId;
    DirectX::XMFLOAT2 position = DirectX::XMFLOAT2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );

    auto device = args->CurrentPoint->PointerDevice;
    auto deviceType = device->PointerDeviceType;
    

       if ( !m_panInUse )   // If no pointer is in this control yet.
    {
       m_panFirstDown = position;                   // Save the location of the initial contact.
       m_panPointerPosition = position;
       m_panPointerID = pointerID;              // Store the id of the pointer using this control.
       m_panInUse = TRUE;
    }
    
}

Usamos este controlador para permitir que la instancia de CameraPanController actual sepa que el controlador de cámara debe tratarse como activo estableciendo m_panInUse en TRUE. De este modo, cuando la aplicación llama a Update , usará los datos de posición actuales para actualizar la ventanilla.

Ahora que hemos establecido los valores base para el movimiento de la cámara cuando el usuario toca la pantalla o hace clic en la ventana de visualización, debemos determinar qué hacer cuando el usuario arrastra la pantalla o mueve el mouse con el botón presionado.

El controlador de eventos OnPointerMoved se activa cada vez que se mueve el puntero, en cada tic que el jugador lo arrastra en la pantalla. Es necesario mantener la aplicación al tanto de la ubicación actual del puntero, y así es como lo hacemos.

OnPointerMoved

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

    m_panPointerPosition = position;
}

Por último, necesitamos desactivar el comportamiento de panorámica de la cámara cuando el reproductor deja de tocar la pantalla. Usamos OnPointerReleased, que se llama cuando se desencadena PointerReleased , para establecer m_panInUse en FALSE y desactivar el movimiento panorámico de la cámara y establecer el identificador de puntero en 0.

OnPointerReleased

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

    m_panInUse = FALSE;
    m_panPointerID = 0;
}

Inicializar los controles táctiles y el estado del controlador

Vamos a enlazar los eventos e inicializar todos los campos de estado básicos del controlador de cámara.

Initialize

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

    // Start receiving touch/mouse events.
    window->PointerPressed += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerPressed);

    window->PointerMoved += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerMoved);

    window->PointerReleased += 
    ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerReleased);


    // Initialize the state of the controller.
    m_panInUse = FALSE;             
    m_panPointerID = 0;

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

}

Initialize toma una referencia a la instancia de CoreWindow de la aplicación como parámetro y registra los controladores de eventos desarrollados para los eventos adecuados en ese CoreWindow.

Obtención y configuración de la posición del controlador de cámara

Vamos a definir algunos métodos para obtener y establecer la posición del controlador de cámara en el espacio de la escena.

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

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

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

}

SetPosition es un método público al que podemos llamar desde nuestra aplicación si necesitamos establecer la posición del controlador de cámara en un punto específico.

get_Position es nuestra propiedad pública más importante: es la forma en que nuestra aplicación obtiene la posición actual del controlador de cámara en el espacio de la escena para que pueda actualizar la ventanilla en consecuencia.

get_FixedLookPoint es una propiedad pública que, en este ejemplo, obtiene un punto de vista normal para el plano x-y. Puede cambiar este método para usar las funciones trigonométricas, sin y cos, al calcular los valores de coordenadas x, y y z si desea crear ángulos más oblicuos para la cámara fija.

Actualización de la información de estado del controlador de cámara

Ahora, realizamos nuestros cálculos que convierten la información de coordenadas de puntero a la que se realiza el seguimiento en m_panPointerPosition en nueva información de coordenadas, respectivamente, de nuestro espacio de escena 3D. Nuestra aplicación llama a este método cada vez que actualizamos el bucle principal de la aplicación. En él calculamos la nueva información de posición que queremos pasar a la aplicación que se usa para actualizar la matriz de vista antes de la proyección en la ventanilla.


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

        if ( pointerDelta.x > 16.0f )        // Leave 32 pixel-wide dead spot for being still.
            m_panCommand.x += 1.0f;
        else
            if ( pointerDelta.x < -16.0f )
                m_panCommand.x += -1.0f;

        if ( pointerDelta.y > 16.0f )        
            m_panCommand.y += 1.0f;
        else
            if (pointerDelta.y < -16.0f )
                m_panCommand.y += -1.0f;
    }

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

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

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

}

Dado que no queremos que el toque o la vibración del mouse hagan que nuestra cámara se desenfoque, establecemos una zona muerta alrededor del puntero con un diámetro de 32 píxeles. También tenemos un valor de velocidad, que en este caso es 1:1 con el recorrido de píxeles del puntero más allá de la zona muerta. Puede ajustar este comportamiento para ralentizar o acelerar la velocidad de movimiento.

Actualización de la matriz de vistas con la nueva posición de la cámara

Ahora podemos obtener una coordenada de espacio de escena en la que nuestra cámara se centra, y que se actualiza cada vez que se le indica a la aplicación que lo haga (cada 60 segundos en el bucle principal de la aplicación, por ejemplo). Este pseudocódigo sugiere el comportamiento de llamada que puede implementar:

 myCameraPanController->Update( m_window ); 

 // Update the view matrix based on the camera position.
 myCamera->MyMethodToComputeViewMatrix(
        myController->get_Position(),        // The position in the 3D scene space.
        myController->get_FixedLookPoint(),      // The point in the space we are looking at.
        DirectX::XMFLOAT3( 0, 1, 0 )                    // The axis that is "up" in our space.
        );  

Felicidades. Has implementado un sencillo conjunto de controles táctiles de movimiento panorámico de cámara en tu juego.