Win10 KeyRot

Windows10 Direct3D でモデルを Key で回転します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの作成

  1. 一般的なキー入力は、タイプされたキーがキーボードバッファにスタックされて、スタックから一文字ずつ取り出します。
    それに対してゲームプログラムでは「今キーが押されている」ことを検知することが必要です。
    今キーが押されていることは、ウインドウハンドル(m_window)を使って GetAsyncKeyState() で調べます。
    例えば左矢印キー(Left)の検出は次のようになります。
        Windows::UI::Core::CoreVirtualKeyStates KeyState;
    
        KeyState = m_window->GetAsyncKeyState(Windows::System::VirtualKey::Left);
        if (bool(KeyState & Windows::UI::Core::CoreVirtualKeyStates::Down))
        {   左矢印キーが押されている
        }
    
  2. ウインドウハンドル(m_window)は App.cpp の SetWindow() 関数で渡されるのですが、キーを調べるのは Sample3DSceneRenderer の Update() 関数です。
    そこで各クラスの Constructor を通じてハンドルをリレーします。
      Class App ⇒ Class App1Main ⇒ Class Sample3DSceneRenderer
    
  3. Win10 Template を参照して DirectX 11 アプリ(ユニバーサル Windows)を作成して下さい。
    カラーキューブが回転しながら描画されます。
    プロジェクトの名前は App1 になっています。
  4. SetWindow() 関数で渡されるウインドウハンドル(m_window)をリレーします。
    1. App.h, App.cpp を修正します。
      App.h にウインドウハンドルを保存する領域を定義します。
      private:
          Windows::UI::Core::CoreWindow^ m_window;
      
      App.cpp の SetWindow() 関数でウインドウハンドルを保存します。
      OutputDebugString() でハンドルが設定されていることを確認しています。
      void App::SetWindow(CoreWindow^ window)
      {   ・・・
          m_window = window;
          if (m_window == nullptr)    OutputDebugString(L"m_window : nullptr\n");
          else   OutputDebugString(L"window : OK\n");
      }
      
      App.cpp の Load() 関数で App1Main を生成するときに m_window を追加します。
      void App::Load(Platform::String^ entryPoint)
      {
          if (m_main == nullptr)
          {
              m_main = std::unique_ptr<App1Main>(new App1Main(m_deviceResources, m_window));
          }
      }
      
    2. App1Main.h, App1Main.cpp を修正します。
      App1Main.h の Constructor の定義を修正して、ウインドウハンドルを保存する領域を定義します。
      public:
          App1Main(const std::shared_ptr<DX::DeviceResources>& deviceResources, Windows::UI::Core::CoreWindow^ window);
              ・・・
          Windows::UI::Core::CoreWindow^ m_window;
      
      App1Main.cpp の Constructor でウインドウハンドルを受け取ります。
      App1Main::App1Main(const std::shared_ptr<DX::DeviceResources>& deviceResources
          , Windows::UI::Core::CoreWindow^ window) :
          m_deviceResources(deviceResources),
          m_window(window)
      {
          ・・・
      }
      
      App1Main.cpp で Sample3DSceneRenderer を生成するときに m_window を追加します。
          // TODO: これをアプリのコンテンツの初期化で置き換えます。
          m_sceneRenderer = std::unique_ptr<Sample3DSceneRenderer>
              (new Sample3DSceneRenderer(m_deviceResources, m_window));
      
    3. Sample3DSceneRenderer.h, Sample3DSceneRenderer.cpp を修正します。
      Sample3DSceneRenderer.h の Constructor の定義を修正します。
      またウインドウハンドルを保存する領域と回転情報を格納する RotY も定義して下さい。
      public:
          Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources
              , Windows::UI::Core::CoreWindow^ window);
              ・・・
          Windows::UI::Core::CoreWindow^ m_window;
          float   RotY = 0;
      
      Sample3DSceneRenderer.cpp の Constructor でウインドウハンドルを保存します。
      これで Sample3DSceneRenderer でキーを調べることが出来るようになります。
      Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources,
          Windows::UI::Core::CoreWindow^ window) :
          m_loadingComplete(false),
          m_degreesPerSecond(45),
          m_indexCount(0),
          m_tracking(false),
          m_deviceResources(deviceResources),
          m_window(window)
      {
          CreateDeviceDependentResources();
          CreateWindowSizeDependentResources();
      }
      
      Sample3DSceneRenderer.cpp の Update() 関数で今キーが押されているかを調べます。
      void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
      {
          if (!m_tracking)
          {
              Windows::UI::Core::CoreVirtualKeyStates KeyState;
              KeyState = m_window->GetAsyncKeyState(Windows::System::VirtualKey::Left);
              if (bool(KeyState& Windows::UI::Core::CoreVirtualKeyStates::Down))
              {
                  RotY -= 0.1f;
                  if (RotY < XM_2PI)    RotY += XM_2PI;
              }
              KeyState = m_window->GetAsyncKeyState(Windows::System::VirtualKey::Right);
              if (bool(KeyState& Windows::UI::Core::CoreVirtualKeyStates::Down))
              {
                  RotY += 0.1f;
                  if (RotY > XM_2PI)    RotY -= XM_2PI;
              }
              Rotate(RotY);
          }
      }
      
  5. Rotate() 関数でモデルを回転して Render() 関数で描画するのですが、修正する必要はありません。
    プログラムを実行するとモデルが自動回転しなくなり、「左矢印キー」または「右矢印キー」を押すとモデルが回転します。
    今回はY軸を中心に回転するだけですが、X軸の回転も追加してみて下さい。
  6. 今回は Constructor を通じてハンドルをリレーしました。
    X2017 KeyRot ではハンドルを直接コピーして渡しています。
    モデルの回転は Win10 Rotate または Win10 MouseRot を参照して下さい。
    OnKeyDown の簡単なプロジェクトは[超初心者のプログラム入門(C/C++)]から[VC-2017 Key Count]を参照して下さい。
    OnKeyDown, OnKeyUp で回転するプロジェクトは Win10 Model & Camera を参照して下さい。

【NOTE】

C++のストアアプリでは、次のコードでウインドウのハンドルを取得できました。
    CoreWindow^ m_window = Window::Current->CoreWindow;

所が Windows10 の[DirectX 11 アプリ(ユニバーサル Windows)]では、コンパイルエラーが表示されます。
エラーは Windows::UI::Xaml; を追加すると消えたのですが、実行すると nullptr でこけます。 (^_^;)
using namespace Windows::UI::Xaml;
 
    CoreWindow^ window = Window::Current->CoreWindow;

そこで今回は App.cpp の SetWindow() 関数で取得したハンドルをリレーして使っています。
ハンドルをリレーするのはちょっと面倒なので DirectX 2017 KeyRot では Class App(window_1) から Class App1Main(window_2) を経由して Class Sample3DSceneRenderer(m_window) にハンドルをコピーする方法でプログラムしてみました。

超初心者のプログラム入門(DirectX Store)