相対マウス移動と 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. たとえば、3D モデラーは、マウス入力を使い、仮想トラックボールをシミュレーションすることによって 3D オブジェクトの向きを設定します。また、ゲームでは、マウスに似たコントローラーを使って、ビュー カメラの方向を変更します。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. 相対マウス値は、ウィンドウ (または画面) 内の絶対 xy 座標値ではなく、前回のフレームを起点としたマウスの移動距離を表します。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. 画面座標を基準としたカーソルの位置は 3D のオブジェクトやシーンでは意味をなさないため、マウス カーソルを非表示にするケースも少なくありません。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.

相対 3D オブジェクト/シーン操作モードに移行させるような操作がユーザーによって行われたとき、アプリは次のことを実行する必要があります。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.
  • null ポインター (nullptr) を設定してマウス カーソルを非表示にする。Hide the mouse cursor by setting it a null pointer (nullptr).

相対 3D オブジェクト/シーン操作モードを解除するような操作がユーザーによって行われたとき、アプリは次のことを実行する必要があります。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::PointerCursornullptr に設定します。The cursor is hidden by setting the CoreWindow::PointerCursor to nullptr.

絶対マウス移動への復帰Returning to absolute mouse movement

アプリが 3D オブジェクト/シーン操作モードから抜け、相対マウス移動が使われなくなったら (メニュー画面に戻ったときなど)、絶対マウス移動の通常の処理に戻す必要があります。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
アプリが 3D オブジェクト/シーン操作モードのとき (カーソルをオフにした状態で相対マウス移動を処理しているとき)、マウスは、チャーム、バック スタック、アプリ バーなどのエッジ UI を呼び出すことができません。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.