次の方法で共有


Marble Maze サンプルの基礎

このトピックでは、Marble Maze プロジェクトの基本的な特性について説明します。たとえば、Windows ランタイム環境で Visual C++ をどのように使うか、どのように作られ、構成され、ビルドされるかなどです。 このトピックでは、コードで使用されるいくつかの規則についても説明します。

Note

このドキュメントに対応するサンプル コードは、DirectX Marble Maze ゲームのサンプルに関するページにあります。

このドキュメントでは、ユニバーサル Windows プラットフォーム (UWP) のゲームを計画および開発する際の次の重要事項について説明します。

  • DirectX UWP ゲームを作るために、Visual Studio で DirectX 11 アプリ (ユニバーサル Windows - C++/CX) テンプレートを使います。
  • Windows ランタイムには、より新しいオブジェクト指向の方法で UWP アプリを開発するためのクラスとインターフェイスが用意されています。
  • Windows ランタイム変数の有効期間を管理するにはハット (^) 記号を付けたオブジェクト参照、COM オブジェクトの有効期間を管理するには Microsoft::WRL::ComPtr、その他のすべてのヒープ割り当て C++ オブジェクトの有効期間を管理するには std::shared_ptr または std::unique_ptr を使います。
  • ほとんどの場合、予期しないエラーの処理には結果コードではなく例外処理を使用します。
  • アプリのエラーの検出には SAL 注釈とコード分析ツールを使用します。

Visual Studio プロジェクトの作成

既にサンプルをダウンロードして展開済みの場合は、Visual Studio で MarbleMaze_VS2017.sln ファイル (C++ フォルダー内) を開くとコードが表示されます。

Marble Maze の Visual Studio プロジェクトを作成する際には、既存のプロジェクトを使用しました。 しかし、DirectX UWP ゲームで必要となる基本的な機能を持つプロジェクトがまだない場合は、Visual Studio DirectX 11 アプリ (ユニバーサル Windows - C++/CX) テンプレートに基づくプロジェクトを作ることをお勧めします。このテンプレートには、基本的な機能を備えた 3D アプリケーションが用意されているためです。 これを行うには、次の手順を実行します。

  1. Visual Studio 2019 で、[ファイル]、[新規]、[プロジェクト] の順に選びます。

  2. [新しいプロジェクトの作成] ウィンドウで、[DirectX 11 アプリ (ユニバーサル Windows - C++/CX)] を選択します。 このオプションが表示されない場合は、必要なコンポーネントがインストールされていない可能性があります。追加コンポーネントをインストールする方法については、「ワークロードやコンポーネントを追加または削除することで Visual Studio 2019 を変更する」をご覧ください。

新しいプロジェクト

  1. [次へ] を選択し、[プロジェクト名]、ファイルが保存される [場所][ソリューション名] を入力し、[作成] を選択します。

DirectX 11 アプリ (ユニバーサル Windows - C++/CX) テンプレートで重要なプロジェクト設定の 1 つは、プログラムが Windows ランタイム言語拡張機能を使えるようにする /ZW オプションです。 このオプションは、Visual Studio テンプレートの使用時に既定で有効になります。 Visual Studio でコンパイラ オプションを設定する方法について詳しくは、「コンパイラとリンカーのオプション (C++/CX)」をご覧ください。

注意 /ZW オプションは、/clr などのオプションとの互換性がありません。 /clr の場合、これは、同じ Visual C++ プロジェクトが .NET Framework と Windows ランタイムの両方をターゲットにすることはできないことを意味します。

 

Microsoft Store で入手するすべての UWP アプリは、アプリ パッケージの形式で提供されます。 アプリ パッケージには、アプリに関する情報が格納されたパッケージ マニフェストが含まれます。 たとえば、アプリの機能 (つまり、保護されたシステム リソースまたはユーザー データへの必要なアクセス) を指定できます。 特定の機能がアプリに必要であると判断した場合は、パッケージ マニフェストを使用して、その必要な機能を宣言します。 また、マニフェストを使用すると、サポートされるデバイスの回転、タイル イメージ、スプラッシュ スクリーンなどのプロジェクト プロパティも指定できます。 マニフェストを編集するには、プロジェクトで Package.appxmanifest を開きます。 アプリ パッケージの詳細については、「アプリのパッケージング」を参照してください。

ゲームのビルド、配置、実行

Visual Studio の上部の、緑色の再生ボタンの左側にあるドロップダウン メニューで、デプロイ構成を選択します。 デバイスのアーキテクチャ (32 ビットの場合は x86、64 ビットの場合は x64) ターゲットとする [デバッグ][ローカル マシン] に設定することをお勧めします。 [リモート マシン] または USB 経由で接続されているデバイスでテストすることもできます。 次に、緑色の再生ボタンをクリックし、ビルドしてデバイスにデプロイします。

デバッグ;x64;ローカル コンピューター

ゲームの制御

Marble Maze の制御には、タッチ、加速度計、ゲーム コントローラー、またはマウスを使用できます。

  • アクティブなメニュー項目を変更するには、コントローラーの方向パッドを使用します。
  • タッチ、コントローラーの A またはスタート ボタン、またはマウスを使用してメニュー項目を選択します。
  • 迷路を傾けるには、タッチ、加速度計、左のサムスティック、またはマウスを使用します。
  • ハイスコア表などのメニューを閉じるには、タッチ、コントローラーの A またはスタート ボタン、またはマウスを使用します。
  • ゲームを一時停止または再開するには、コントローラーのスタート ボタンまたはキーボードの P キーを使用します。
  • ゲームを再起動するには、コントローラーの [戻る] ボタンまたはキーボードの Home キーを使用します。
  • ハイスコア テーブルが表示されているときに、コントローラーの [戻る] ボタンまたはキーボードの [ホーム] キーを使用すると、すべてのスコアがクリアされます。

コードの規則

Windows ランタイムは、特別なアプリケーション環境でのみ動作する UWP アプリの作成に使用できるプログラミング インターフェイスです。 このようなアプリは、認定された関数、データ型、デバイスを使い、Microsoft Store から配布されます。 最下位レベルでは、Windows ランタイムはアプリケーション バイナリ インターフェイス (ABI) で構成されます。 ABI は、JavaScript、.NET 言語、Visual C++ などの複数のプログラミング言語から Windows ランタイム API にアクセスできるようにする低水準のバイナリ コントラクトです。

JavaScript および .NET から Windows ランタイム API を呼び出すには、各言語環境に固有のプロジェクションが必要です。 JavaScript または .NET から Windows ランタイム API を呼び出すときは、プロジェクションを呼び出し、そのプロジェクションが基になる ABI 関数を呼び出します。 C++ では直接 ABI 関数を呼び出すことができますが、Microsoft は C++ に対してもプロジェクションを提供しています。高いパフォーマンスを維持したままで、はるかに簡単に Windows ランタイム API を使用できるためです。 Microsoft は、Windows ランタイムのプロジェクションを特別にサポートする Visual C++ の言語拡張機能も提供しています。 これらの言語拡張機能の多くは、C++ または CLI 言語の構文に似ています。 ただし、ネイティブ アプリは共通言語ランタイム (CLR) をターゲットとするのではなく、この構文を使用して Windows ランタイムをターゲットとします。 オブジェクト参照、またはハット (^) 修飾子は、この新しい構文の重要な部分です。これを使用すると、参照カウントによってランタイム オブジェクトを自動的に削除できるためです。 オブジェクトがスコープの外に出るか、すべての参照を nullptr に設定するなど、オブジェクトが他のコンポーネントから参照されていない場合、Windows ランタイム オブジェクトの有効期間を管理する AddRefRelease などのメソッドを呼び出す代わりに、ランタイムはオブジェクトを削除します。 Visual C++ を使用して UWP アプリを作成する際のもう 1 つの重要な部分は、ref new キーワードです。 参照カウントされる Windows ランタイム オブジェクトを作成するには、new ではなく ref new を使用します。 詳細については、型システム (C++/CX) に関する記事を参照してください。

重要

^ref new を使用する必要があるのは、Windows ランタイム オブジェクトを作成するときと Windows ランタイム コンポーネントを作成するときだけです。 Windows ランタイムを使用しないコア アプリケーション コードを記述する際には C++ の標準構文を使用できます。

Marble Maze は、ヒープに割り当てられたオブジェクトを ^Microsoft::WRL::ComPtr を使って管理し、メモリ リークを最小限に抑えます。 Windows ランタイム変数の有効期間を管理するときは ^ を、COM 変数の有効期間を管理するとき (DirectX 使用時など) は ComPtr を使うようにお勧めします。ヒープに割り当てられるその他すべての C++ オブジェクトは、std::shared_ptr または std::unique_ptr を使って管理するようにします。

 

C++ UWP アプリで利用できる言語拡張機能の詳細については、「Visual C++ の言語リファレンス (C++/CX)」をご覧ください。

エラー処理

Marble Maze では、予期しないエラーを処理する主な方法として例外処理を使用します。 従来、ゲーム コードではエラーを示すためにログまたはエラー コード (HRESULT 値など) が使用されてきましたが、例外処理には 2 つの大きな利点があります。 まず、コードの読み取りと保守が容易になります。 コードの観点から見た場合、例外処理は、エラーを処理できるルーチンにエラーを伝達するためのより効率的な方法です。 エラー コードを使用する場合は通常、各関数が明示的にエラーを伝達する必要があります。 もう 1 つの利点は、エラーの場所およびコンテキストで直ちに停止できるように、例外発生時に Visual Studio デバッガーを中断するように構成できるという点です。 Windows ランタイムでも、例外処理が広範囲に使用されています。 したがって、コードに例外処理を使用することで、すべてのエラー処理を 1 つのモデルにまとめることができます。

エラー処理モデルでは、次の規則を使用することをお勧めします。

  • 例外を使用して予期しないエラーを通知します。

  • コードのフロー制御には例外を使用しないでください。

  • 安全に処理して回復できる例外だけをキャッチします。 それ以外の場合は、例外をキャッチせずにアプリをそのまま終了させます。

  • HRESULT を返す DirectX ルーチンを呼び出す場合は、DX::ThrowIfFailed 関数を使用します。 この関数は DirectXHelper.h に定義されています。 指定された HRESULT がエラー コードの場合、ThrowIfFailed は例外をスローします。 たとえば、E_POINTER が渡されると ThrowIfFailed から Platform::NullReferenceException がスローされます。

    ThrowIfFailed を使用する際は、次の例に示すように、DirectX の呼び出しを別の行に配置してコードを読みやすくします。

    // Identify the physical adapter (GPU or card) this device is running on.
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(
        dxgiDevice->GetAdapter(&dxgiAdapter)
        );
    
  • 予期しないエラーには HRESULT の使用を避けることをお勧めしますが、それよりも重要なのは、コードのフロー制御に例外処理を使用しないことです。 したがって、コードのフローを制御するために必要な場合には、HRESULT 戻り値を使用することをお勧めします。

SAL 注釈

アプリのエラーの検出には SAL 注釈とコード分析ツールを使用します。

Microsoft のソース コード注釈言語 (SAL: Source Code Annotation Language) を使用すると、関数がパラメーターをどのように使用するかを示す注釈 (説明) を付けることができます。 SAL 注釈は、戻り値の説明にも使用されます。 SAL 注釈は、C/C++ Code Analysis ツールと連携して C および C++ ソース コードの欠陥を検出します。 このツールで報告される一般的なコーディング エラーとして、バッファー オーバーラン、初期化されていないメモリ、Null ポインターの逆参照、メモリ リーク、リソース リークなどがあります。

BasicLoader.h で宣言されている BasicLoader::LoadMesh メソッドについて考えてみましょう。 このメソッドは、_In_ を使って filename が入力パラメーターである (つまり、読み取られるだけである) ことを指定します。また、_Out_ を使って vertexBufferindexBuffer が出力パラメーターである (つまり、書き込まれるだけである) ことを指定します。さらに、_Out_opt_ を使って vertexCountindexCount が省略可能な出力パラメーターである (書き込まれる場合がある) ことを指定します。 vertexCountindexCount は省略可能な出力パラメーターであるため、nullptr にすることができます。 C/C++ Code Analysis ツールは、このメソッドの呼び出しを調べて、渡されたパラメーターがこれらの条件を満たしていることを確認します。

void LoadMesh(
    _In_ Platform::String^ filename,
    _Out_ ID3D11Buffer** vertexBuffer,
    _Out_ ID3D11Buffer** indexBuffer,
    _Out_opt_ uint32* vertexCount,
    _Out_opt_ uint32* indexCount
    );

アプリのコード分析を行うには、メニュー バーで [ビルド]、[ソリューションでコード分析を実行] の順に選択します。 コード分析について詳しくは、コード分析による C/C++ コード品質の分析に関するページをご覧ください。

使用できるすべての注釈のリストは sal.h で定義されています。 詳細については、SAL 注釈の詳細については、「SAL 注釈」を参照してください。

次のステップ

Marble Maze アプリケーション コードの構造、および、DirectX UWP アプリの構造と従来のデスクトップ アプリケーションの構造の違いについては、「Marble Maze のアプリケーション構造」を参照してください。