Поделиться через


Сенсорные элементы управления для игр

Узнайте, как добавить базовые элементы управления сенсорными элементами в игру C++ универсальная платформа Windows (UWP) с помощью DirectX. Мы покажем, как добавить сенсорные элементы управления для перемещения камеры фиксированной плоскости в среде Direct3D, где перетаскивание с помощью пальца или пера сдвигает перспективу камеры.

Вы можете включить эти элементы управления в игры, где вы хотите, чтобы игрок перетаскивал прокрутку или сдвиг по трехмерной среде, например карта или плейфилд. Например, в стратегии или головоломке вы можете использовать эти элементы управления, чтобы позволить игроку просматривать игровую среду, большую, чем экран, передвигая влево или вправо.

Обратите внимание , что код также работает с элементами управления сдвига на основе мыши. Связанные с указателем события абстрагируются среда выполнения Windows API, поэтому они могут обрабатывать события указателя на основе касания или мыши.

 

Задачи

  • Создайте простой элемент управления перетаскиванием сенсорного ввода для сдвига камеры фиксированной плоскости в игре DirectX.

Настройка базовой инфраструктуры событий сенсорного ввода

Сначала мы определим базовый тип контроллера , CameraPanController, в данном случае. Здесь мы определяем контроллер как абстрактную идею, набор поведения, который может выполнять пользователь.

Класс CameraPanController — это регулярно обновляемая коллекция сведений о состоянии контроллера камеры и предоставляет способ получения этой информации из цикла обновления.

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

Теперь создадим заголовок, определяющий состояние контроллера камеры, а также основные методы и обработчики событий, реализующие взаимодействие контроллера камеры.

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

Частные поля содержат текущее состояние контроллера камеры. Давайте рассмотрим их.

  • m_position — это положение камеры в пространстве сцены. В этом примере значение z-координаты исправлено по 0. Для представления этого значения можно использовать DirectX::XMFLOAT2, но для целей этого примера и будущей расширяемости мы используем DirectX::XMFLOAT3. Мы передаем это значение через свойство get_Position самому приложению, чтобы он смог соответствующим образом обновить окно просмотра.
  • m_panInUse — это логическое значение, указывающее, активна ли операция сдвига; или, более конкретно, касается ли проигрыватель экрана и перемещает камеру.
  • m_panPointerID — это уникальный идентификатор указателя. Мы не будем использовать это в примере, но рекомендуется связать класс состояния контроллера с определенным указателем.
  • m_panFirstDown — это точка на экране, где проигрыватель сначала коснулся экрана или щелкнул мышь во время действия сдвига камеры. Мы используем это значение позже, чтобы задать мертвую зону, чтобы предотвратить дрожание при касании экрана, или если мышь встряхивает немного.
  • m_panPointerPosition — это точка на экране, где проигрыватель в настоящее время переместил указатель. Мы используем его, чтобы определить, в каком направлении игрок хотел двигаться, проверив его относительно m_panFirstDown.
  • m_panCommand — это окончательная вычисленная команда для контроллера камеры: вверх, вниз, слева или справа. Так как мы работаем с камерой, фиксированной на плоскости x-y, это может быть значение DirectX::XMFLOAT2 вместо этого.

Эти 3 обработчика событий используются для обновления сведений о состоянии контроллера камеры.

  • OnPointerPressed — это обработчик событий, который вызывается приложением, когда игроки нажимают пальцем на сенсорной поверхности, а указатель перемещается в координаты нажатия.
  • OnPointerMoved — это обработчик событий, который вызывается приложением, когда проигрыватель проводит пальцем по сенсорной поверхности. Он обновляется новыми координатами пути перетаскивания.
  • OnPointerReleased — это обработчик событий, который вызывается приложением при удалении нажатия пальца с сенсорной поверхности.

Наконец, мы используем эти методы и свойства для инициализации, доступа и обновления сведений о состоянии контроллера камеры.

  • Инициализация — это обработчик событий, вызываемый приложением для инициализации элементов управления и присоединения их к объекту CoreWindow , описывающего окно отображения.
  • SetPosition — это метод, который вызывает приложение для задания координат (x, y и z) элементов управления в пространстве сцены. Обратите внимание, что наша координата z составляет 0 в рамках этого руководства.
  • get_Position — это свойство, к которому обращается наше приложение, чтобы получить текущую позицию камеры в пространстве сцены. Это свойство используется в качестве способа взаимодействия текущей позиции камеры с приложением.
  • get_FixedLookPoint — это свойство, к которому обращается наше приложение, чтобы получить текущую точку, к которой сталкивается камера контроллера. В этом примере он заблокирован как обычный для плоскости x-y.
  • Обновление — это метод, который считывает состояние контроллера и обновляет положение камеры. Вы постоянно вызываете это <что-то> из основного цикла приложения, чтобы обновить данные контроллера камеры и положение камеры в пространстве сцены.

Теперь у вас есть все компоненты, необходимые для реализации сенсорных элементов управления. Вы можете определить, когда и где произошли события касания или указателя мыши, а также то, что такое действие. Вы можете задать положение и ориентацию камеры относительно пространства сцены и отслеживать изменения. Наконец, вы можете связать новую позицию камеры с вызывающим приложением.

Теперь давайте соединим эти части вместе.

Создание основных событий касания

Диспетчер событий среда выполнения Windows предоставляет 3 события, которые мы хотим, чтобы наше приложение обрабатывалось:

Эти события реализуются в типе CoreWindow . Предполагается, что у вас есть объект CoreWindow для работы. Дополнительные сведения см. в разделе "Настройка приложения UWP C++ для отображения представления DirectX".

По мере запуска этих событий обработчики обновляют сведения о состоянии контроллера камеры, определенные в наших частных полях.

Во-первых, давайте заполняем обработчики событий указателя касания. В первом обработчике событий OnPointerPressed мы получаем координаты указателя x-y из CoreWindow, который управляет отображением, когда пользователь прикасается к экрану или щелкает мышь.

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

Мы используем этот обработчик, чтобы сообщить текущему экземпляру CameraPanController , что контроллер камеры должен рассматриваться как активный, задав m_panInUse значение TRUE. Таким образом, когда приложение вызывает Update , оно будет использовать текущие данные положения для обновления окна просмотра.

Теперь, когда пользователь прикасается к экрану или нажимает нажатие кнопки в окне отображения, мы должны определить, что делать, когда пользователь перетаскивает экран или перемещает мышь с нажатием кнопки.

Обработчик событий OnPointerMoved запускается всякий раз, когда указатель перемещается, при каждом тике, который проигрыватель перетаскивает его на экране. Мы должны держать приложение в курсе текущего расположения указателя, и это то, как мы это делаем.

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

Наконец, необходимо отключить поведение сдвига камеры, когда проигрыватель перестает касаться экрана. Мы используем OnPointerReleased, который вызывается при срабатывании PointerReleased, чтобы задать m_panInUse значение FALSE и отключить перемещение сдвига камеры и задать идентификатор указателя равным 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;
}

Инициализация сенсорных элементов управления и состояния контроллера

Давайте подключим события и инициализировать все основные поля состояния контроллера камеры.

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

}

Инициализация принимает ссылку на экземпляр CoreWindow приложения в качестве параметра и регистрирует обработчики событий, разработанные для соответствующих событий в этом CoreWindow.

Получение и настройка положения контроллера камеры

Давайте определим некоторые методы, чтобы получить и задать положение контроллера камеры в пространстве сцены.

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 — это общедоступный метод, который можно вызвать из нашего приложения, если необходимо установить положение контроллера камеры в определенную точку.

get_Position является нашим самым важным общедоступным свойством: это то, как наше приложение получает текущее положение контроллера камеры в пространстве сцены, чтобы он смог соответствующим образом обновить окно просмотра.

get_FixedLookPoint — это общедоступное свойство, которое в этом примере получает точку внешнего вида, которая является нормальной для плоскости x-y. Этот метод можно изменить, чтобы использовать тригонометрические функции, грех и косы, при вычислении значений координат x, y и z, если вы хотите создать более косые угла для фиксированной камеры.

Обновление сведений о состоянии контроллера камеры

Теперь мы выполняем наши вычисления, которые преобразуют данные координат указателя, отслеживаемые в m_panPointerPosition , в новые сведения о координатах, соответствующие 3D-пространства сцены. Наше приложение вызывает этот метод каждый раз, когда мы обновляем цикл основного приложения. В нем вычисляется новая информация о позиции, которую мы хотим передать приложению, которое используется для обновления матрицы представления перед проекцией в окно просмотра.


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

}

Потому что мы не хотим, чтобы сенсорный или мыши рыжий, чтобы сделать нашу камеру сдвига рывком, мы устанавливаем мертвую зону вокруг указателя с диаметром 32 пикселей. У нас также есть значение скорости, которое в данном случае равно 1:1 с обходом пикселя указателя мимо мертвой зоны. Это поведение можно изменить, чтобы замедлить или ускорить скорость движения.

Обновление матрицы просмотра с помощью новой позиции камеры

Теперь мы можем получить координату пространства сцены, на которую ориентирована наша камера, и которая обновляется всякий раз, когда вы сообщаете приложению сделать это (каждые 60 секунд в основном цикле приложения, например). Этот псевдокод предлагает поведение вызова, который можно реализовать:

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

Поздравляем! Вы реализовали простой набор элементов управления касанием камеры в игре.