Относительное перемещение мыши и CoreWindowRelative mouse movement and CoreWindow

Распространенным средством управления в играх служит мышь, привычная пользователям и неотъемлемая в играх таких жанров, как "стрелялки" от первого и от третьего лица, стратегические игры в реальном времени и другие.In games, the mouse is a common control option that is familiar to many players, and is likewise essential to many genres of games, including first- and third-person shooters, and real-time strategy games. Здесь мы рассмотрим реализацию относительных элементов управления для мыши, которые не используют системный курсор и не возвращают абсолютные экранные координаты, а отслеживают изменение значений пикселей при перемещении мыши.Here we discuss the implementation of relative mouse controls, which don't use the system cursor and don't return absolute screen coordinates; instead, they track the pixel delta between mouse movements.

Во многих приложениях, например в играх, мышь используется в качестве основного устройства ввода.Some apps, such as games, use the mouse as a more general input device. Скажем, ввод с помощью мыши может применяться в трехмерной модели, чтобы задавать направление трехмерному объекту при имитации виртуального трекбола, или в игре с помощью мыши может изменяться направление камеры (через элементы управления мышью и обзором).For example, a 3-D modeler might use mouse input to orient a 3-D object by simulating a virtual trackball; or a game might use the mouse to change the direction of the viewing camera via mouse-look controls.

При таких сценариях приложению нужны относительные данные ввода с мыши.In these scenarios, the app requires relative mouse data. Относительные значения перемещения мыши означают дальность перемещения мыши относительно предыдущего кадра, а не абсолютные координаты в пределах окна или экрана.Relative mouse values represent how far the mouse moved since the last frame, rather than the absolute x-y coordinate values within a window or screen. Кроме того, приложения зачастую скрывают курсор мыши, так как положение курсора относительно экранных координат несущественно при управлении трехмерным объектом или пространством.Also, apps often hide the mouse cursor since the position of the cursor with respect to the screen coordinates is not relevant when manipulating a 3-D object or scene.

Если пользователь выполняет действие, которое переводит приложение в режим относительного управления трехмерным объектом или пространством, приложение должно:When the user takes an action that moves the app into a relative 3-D object/scene manipulation mode, the app must:

  • игнорировать обработку сигналов мыши по умолчанию;Ignore default mouse handling.
  • включить относительную обработку сигналов мыши;Enable relative mouse handling.
  • скрыть курсор мыши, установив пустой указатель (nullptr).Hide the mouse cursor by setting it a null pointer (nullptr).

Если пользователь выполняет действие, которое выводит приложение из режима относительного управления трехмерным объектом или пространством, приложение должно:When the user takes an action that moves the app out of a relative 3-D object/scene manipulation mode, the app must:

  • включить обработку сигналов мыши по умолчанию;Enable default/absolute mouse handling.
  • выключить относительную обработку сигналов мыши;Turn off relative mouse handling.
  • задать для курсора мыши значение, отличное от null (отчего курсор становится виден).Set the mouse cursor to a non-null value (which makes it visible).

Примечание.Note
При такой схеме абсолютное положение курсора мыши сохраняется при переходе в относительный режим, когда курсор скрыт.With this pattern, the location of the absolute mouse cursor is preserved on entering the cursorless relative mode. Курсор вновь появится в той же координате экрана, что и до перехода в режим относительной обработки сигналов мыши.The cursor re-appears in the same screen coordinate location as it was previous to enabling the relative mouse movement mode.

Обработка относительных значений перемещения мышиHandling relative mouse movement

Чтобы получить доступ к относительным значениям перемещения мыши, выполните регистрацию события MouseDevice::MouseMoved, как показано ниже.To access relative mouse delta values, register for the MouseDevice::MouseMoved event as shown here.



// register handler for relative mouse movement events
Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
        ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &MoveLookController::OnMouseMoved);




void MoveLookController::OnMouseMoved(
    _In_ Windows::Devices::Input::MouseDevice^ mouseDevice,
    _In_ Windows::Devices::Input::MouseEventArgs^ args
    )
{
    float2 pointerDelta;
    pointerDelta.x = static_cast<float>(args->MouseDelta.X);
    pointerDelta.y = static_cast<float>(args->MouseDelta.Y);

    float2 rotationDelta;
    rotationDelta = pointerDelta * ROTATION_GAIN;   // scale for control sensitivity

    // update our orientation based on the command
    m_pitch -= rotationDelta.y;                     // mouse y increases down, but pitch increases up
    m_yaw   -= rotationDelta.x;                     // yaw defined as CCW around y-axis

    // limit pitch to straight up or straight down
    float limit = (float)(M_PI/2) - 0.01f;
    m_pitch = (float) __max( -limit, m_pitch );
    m_pitch = (float) __min( +limit, m_pitch );

    // keep longitude in useful range by wrapping
    if ( m_yaw >  M_PI )
        m_yaw -= (float)M_PI*2;
    else if ( m_yaw < -M_PI )
        m_yaw += (float)M_PI*2;
}

Обработчик событий OnMouseMoved в данном примере кода выполняет преобразование для просмотра в зависимости от перемещений мыши.The event handler in this code example, OnMouseMoved, renders the view based on the movements of the mouse. Положение указателя мыши передается в обработчик в качестве объекта MouseEventArgs.The position of the mouse pointer is passed to the handler as a MouseEventArgs object.

Пропускайте обработку данных об абсолютном положении мыши от события CoreWindow::PointerMoved, если ваше приложение переходит в режим обработки относительных значений перемещения мыши.Skip over processing of absolute mouse data from the CoreWindow::PointerMoved event when your app changes to handling relative mouse movement values. При этом пропускайте эти данные, только если событие CoreWindow::PointerMoved наступило в результате ввода с помощью мыши (а не сенсорного ввода).However, only skip this input if the CoreWindow::PointerMoved event occurred as the result of mouse input (as opposed to touch input). Курсор скрыт, потому что для свойства CoreWindow::PointerCursor установлено значение nullptr.The cursor is hidden by setting the CoreWindow::PointerCursor to nullptr.

Возвращение в режим обработки абсолютных значений перемещения мышиReturning to absolute mouse movement

Когда приложение выходит из режима относительного управления трехмерным объектом или пространством и более не использует относительные значения перемещения мыши (например, при возвращении в экран меню), вернитесь к обычной обработке абсолютных значений перемещения мыши.When the app exits the 3-D object or scene manipulation mode and no longer uses relative mouse movement (such as when it returns to a menu screen), return to normal processing of absolute mouse movement. Теперь нужно прекратить чтение относительных данных о положении мыши, перезапустить обработку обычных событий мыши (и указателя) и установить для CoreWindow::PointerCursor значение, отличное от null.At this time, stop reading relative mouse data, restart the processing of standard mouse (and pointer) events, and set CoreWindow::PointerCursor to non-null value.

Примечание.Note
Когда приложение находится в режиме относительного управления трехмерным объектом или пространством (обрабатывает относительные значения перемещения мыши при отключенном курсоре), с помощью мыши невозможно вызывать элементы пользовательского интерфейса, расположенные по краям, например чудо-кнопки, кнопку "Назад" или панель приложения.When your app is in the 3-D object/scene manipulation mode (processing relative mouse movements with the cursor off), the mouse cannot invoke edge UI such as the charms, back stack, or app bar. Поэтому важно предусмотреть способ выхода из данного режима, например с помощью клавиши ESC.Therefore, it is important to provide a mechanism to exit this particular mode, such as the commonly used Esc key.