상대 마우스 이동 및 CoreWindow

게임에서 마우스는 많은 플레이어에게 친숙한 일반적인 제어 옵션이며, 마찬가지로 1인칭 및 3인칭 슈팅 게임, 실시간 전략 게임을 비롯한 수많은 게임 장르에서 필수입니다. 여기서는 시스템 커서를 사용하지 않고 절대 화면 좌표를 반환하지 않는 상대 마우스 컨트롤의 구현에 대해 설명합니다. 대신 마우스 이동 간의 픽셀 델타를 추적합니다.

게임 등의 일부 앱은 마우스를 보다 일반적인 입력 장치로 사용합니다. 예를 들어, 3차원 모델러는 마우스 입력을 사용하여 가상 트랙볼을 시뮬레이션하고 3차원 개체의 방향을 지정합니다. 또는 게임에서 마우스를 사용하여 마우스 모양 컨트롤을 통해 보기 카메라 방향을 변경할 수 있습니다.

이러한 시나리오에서는 앱에 상대 마우스 데이터가 필요합니다. 상대 마우스 값은 창이나 화면 내의 절대 x-y 좌표 값이 아니라 마지막 프레임 이후 마우스가 이동한 정도를 나타냅니다. 또한 앱은 3차원 개체 또는 장면을 조작할 경우 화면 좌표와 관련된 커서의 위치가 관련이 없으므로 마우스 커서를 숨기는 경우가 많습니다.

사용자가 앱을 상대 3차원 개체/장면 조작 모드로 이동하는 작업을 수행하는 경우 앱은 다음을 수행해야 합니다.

  • 기본 마우스 처리 무시.
  • 상대 마우스 처리의 사용 설정.
  • 마우스 커서를 null 포인터(nullptr)로 설정하여 숨기기.

사용자가 앱을 상대 3차원 개체/장면 조작 모드에서 이동하는 작업을 수행하는 경우 앱은 다음을 수행해야 합니다.

  • 기본/절대 마우스 처리 사용 설정.
  • 상대 마우스 처리 끄기.
  • 마우스 커서를 null이 아닌 값(표시)으로 설정.

참고
이 패턴을 사용하면 커서가 없는 상대 모드로 전환 시 절대 마우스 커서의 위치가 유지됩니다. 커서는 상대 마우스 이동 모드를 사용하도록 설정하기 전과 동일한 화면 좌표 위치에 다시 나타납니다.

상대 마우스 이동 처리

상대 마우스 델타 값에 액세스하려면 다음과 같이 MouseDevice::MouseMoved 이벤트에 등록합니다.



// 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는 마우스 이동에 따라 보기를 렌더링합니다. 마우스 포인터의 위치는 MouseEventArgs 개체로 처리기에 전달됩니다.

앱이 상대 마우스 이동 값 처리로 변경될 경우 CoreWindow::PointerMoved 이벤트에서 절대 마우스 데이터 처리를 건너뜁니다. 그러나 터치 입력이 아니라 마우스 입력의 결과로 CoreWindow::PointerMoved 이벤트가 발생한 경우에만 이 입력을 건너뜁니다. CoreWindow::PointerCursornullptr로 설정하여 커서를 숨깁니다.

절대 마우스 이동으로 돌아가기

앱이 3차원 개체 또는 장면 조작 모드를 종료하고 더 이상 상대 마우스 이동(예: 메뉴 화면으로 돌아갈 때)을 사용하지 않는 경우, 정상적인 절대 마우스 이동의 처리로 돌아갑니다. 이때 상대 마우스 데이터 읽기를 중지하고, 표준 마우스(및 포인터) 이벤트 처리를 다시 시작하고, CoreWindow::PointerCursor를 null이 아닌 값으로 설정합니다.

참고
앱이 3차원 개체/장면 조작 모드(커서가 꺼진 상대 마우스 이동 처리)에 있는 경우, 마우스는 참, 뒤로 스택 또는 앱 바와 같은 에지 UI를 호출할 수 없습니다. 따라서 일반적으로 사용되는 Esc 키 등 이 특정 모드를 종료하는 메커니즘을 제공하는 것이 중요합니다.