ゲーム プロジェクトのセットアップ
注意
このトピックは、「DirectX を使った単純なユニバーサル Windows プラットフォーム (UWP) ゲームの作成」チュートリアル シリーズの一部です。 リンク先のトピックでは、このシリーズのコンテキストを説明しています。
ゲームを開発するための最初の手順は、Microsoft Visual Studio でプロジェクトを作成することです。 ゲーム開発専用のプロジェクトを構成すると、後でテンプレートの一種として再利用できます。
目標
- プロジェクト テンプレートを使用して Visual Studio で新しいプロジェクトを作成します。
- App クラスのソース ファイルを調べて、ゲームのエントリ ポイントと初期化について理解します。
- ゲーム ループを確認します。
- プロジェクトの package.appxmanifest ファイルを確認します。
Visual Studio での新しいプロジェクトの作成
Note
C++/WinRT Visual Studio Extension (VSIX) と NuGet パッケージ (両者が連携してプロジェクト テンプレートとビルドをサポート) のインストールと使用など、C++/WinRT 開発用に Visual Studio を設定する方法については、Visual Studio での C++/WinRT のサポートに関する記事を参照してください。
まず、最新バージョンの C++/WinRT Visual Studio 拡張機能 (VSIX) をインストール (または更新) します。上記の注を参照してください。 次に、Visual Studio で [コア アプリ (C++/WinRT)] プロジェクト テンプレートに基づいて新しいプロジェクトを作成します。 Windows SDK の最新の一般公開された (プレビュー以外の) バージョンを対象とします。
App クラスを確認して IFrameworkViewSource と IFrameworkView について理解する
コア アプリ プロジェクトで、ソース コード ファイル App.cpp
を開きます。 ここには、アプリとそのライフサイクルを表す App クラスの実装があります。 今回の場合はもちろん、アプリがゲームであることはわかっています。 ユニバーサル Windows プラットフォーム (UWP) アプリの初期化方法について、より一般的な説明をするために、ここでは "アプリ" と呼びます。
wWinMain 関数
wWinMain 関数は、アプリのエントリ ポイントです。 wWinMain は、次のようになります (App.cpp
から引用)。
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
CoreApplication::Run(winrt::make<App>());
}
App クラスのインスタンス (作成される App の唯一のインスタンス) を作成し、静的メソッド CoreApplication.Run に渡します。 CoreApplication.Run では、IFrameworkViewSource インターフェイスが想定されることに注意してください。 そのため、App クラスではこのインターフェイスを実装する必要があります。
このトピックの次の 2 つのセクションでは、IFrameworkViewSource および IFrameworkView インターフェイスについて説明します。 これらのインターフェイス (およびCoreApplication) は、アプリがビュープロバイダーで Windows を提供する方法を表します。 Windows では、そのビュー プロバイダーを使用して Windows シェルにアプリを接続し、アプリケーション ライフサイクル イベントを処理できるようにします。
IFrameworkViewSource インターフェイス
App クラスでは、下のリストに示すように、実際に IFrameworkViewSource が実装されます。
struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
...
IFrameworkView CreateView()
{
return *this;
}
...
}
IFrameworkViewSource を実装するオブジェクトは、"ビュー プロバイダー ファクトリー" オブジェクトです。 このオブジェクトのジョブは、"ビュー プロバイダー" オブジェクトを作成して返すことです。
IFrameworkViewSource には、IFrameworkViewSource::CreateView という 1 つのメソッドがあります。 Windows では、CoreApplication.Run に渡すオブジェクトに対してこの関数が呼び出されます。 上に示したように、このメソッドの App::CreateView 実装は *this
を返します。 つまり、App オブジェクトは自身を返します。 IFrameworkViewSource::CreateView の戻り値の型は IFrameworkView であるため、App クラスでも "その" インターフェイスを実装する必要があることに従います。 そのため、上記のリストにはこれも含まれています。
IFrameworkView インターフェイス
IFrameworkView を実装するオブジェクトは、"ビュー プロバイダー" オブジェクトです。 ここでは、そのビュー プロバイダーを Windows に提供しました。 それは、wWinMain で作成したのと同じ App オブジェクトです。 そのため、App クラスは、"ビュー プロバイダー ファクトリー" と "ビュー プロバイダー" の両方として機能します。
これで Windows では、IFrameworkView のメソッドの App クラスの実装を呼び出すことができます。 これらのメソッドの実装において、アプリには初期化などのタスクを実行し、必要なリソースの読み込みを開始し、適切なイベントハンドラーを接続し、アプリが出力を表示するために使用する CoreWindow を受け取る機会があります。
IFrameworkView のメソッドの実装は、下に示す順番で呼び出されます。
- 初期化する
- SetWindow
- [読み込み]
- CoreApplicationView::Activated イベントが発生します。 そのため、そのイベントを処理するために (必要に応じて) 登録した場合は、この時点で OnActivated ハンドラーが呼び出されます。
- [実行]
- Uninitialize
これらのメソッドの署名を示す App クラス (App.cpp
内) のスケルトンは次のとおりです。
struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
...
void Initialize(Windows::ApplicationModel::Core::CoreApplicationView const& applicationView) { ... }
void SetWindow(Windows::UI::Core::CoreWindow const& window) { ... }
void Load(winrt::hstring const& entryPoint) { ... }
void OnActivated(
Windows::ApplicationModel::Core::CoreApplicationView const& applicationView,
Windows::ApplicationModel::Activation::IActivatedEventArgs const& args) { ... }
void Run() { ... }
void Uninitialize() { ... }
...
}
ここでは、IFrameworkView について簡単に説明しました。 これらのメソッドの詳細と実装方法については、「ゲームの UWP アプリ フレームワークの定義」を参照してください。
プロジェクトを整理する
プロジェクト テンプレートから作成したコア アプリ プロジェクトには、この時点で整理する必要がある機能が含まれています。 その後に、プロジェクトを使用して、シューティング ギャラリー ゲーム(Simple3DGameDX) を再作成できます。 App.cpp
内の App クラスに次の変更を加えます。
- そのデータ メンバーを削除します。
- OnPointerPressed、OnPointerMoved、AddVisual を削除します。
- SetWindow からコードを削除します。
プロジェクトがビルドされて実行されますが、クライアント領域には単色のみが表示されます。
ゲーム ループ
ゲーム ループがどのようなものか理解するには、ダウンロードした Simple3DGameDX サンプル ゲームのソース コードを確認します。
App クラスには、GameMain 型の m_main というデータ メンバーがあります。 このメンバーは、App::Run で次のように使用されます。
void Run()
{
m_main->Run();
}
GameMain::Run は GameMain.cpp
にあります。 これはゲームのメイン ループであり、最も重要な機能を示す大まかな概要は以下のとおりです。
void GameMain::Run()
{
while (!m_windowClosed)
{
if (m_visible)
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
Update();
m_renderer->Render();
m_deviceResources->Present();
}
else
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
ここでは、このメイン ゲーム ループの機能について簡単に説明します。
ゲームのウィンドウを閉じなければ、すべてのイベントがディスパッチされ、タイマーが更新され、グラフィックス パイプラインの結果がレンダリングされて表示されます。 これらの事項についてはさらに説明が必要なため、「ゲームの UWP アプリ フレームワークの定義」、「レンダリング フレームワーク I: レンダリングの概要」、「レンダリング フレームワーク II: ゲームのレンダリング」のトピックで詳細を説明します。 ここで示すのは、UWP DirectX ゲームの基本的なコード構造です。
package.appxmanifest ファイルを確認して更新する
Package.appxmanifest ファイルには、UWP プロジェクトに関するメタデータが含まれています。 これらのメタデータは、ゲームのパッケージ化と起動、および Microsoft Store への送信に使用されます。 このファイルには、プレイヤーのシステムがゲームの実行に必要なリソースへのアクセスを提供するための重要な情報も含まれます。
ソリューション エクスプローラーで Package.appxmanifest ファイルをダブルクリックして、マニフェスト デザイナーを起動します。
package.appxmanifest ファイルとパッケージ化について詳しくは、マニフェスト デザイナーに関するページをご覧ください。 それでは、[機能] タブとそのオプションを見てみましょう。
グローバルなハイ スコア ボードのためのインターネットへのアクセスなど、ゲームで使う機能を選択しないと、該当するリソースにも機能にもアクセスできません。 新しいゲームを作る場合、ゲームによって呼び出される API に必要な機能をすべて忘れずに選択してください。
それでは、Simple3DGameDX サンプル ゲームに付属しているファイルの残りの部分を見てみましょう。
その他の重要なライブラリとソース コード ファイルを確認する
自分用のゲーム プロジェクト テンプレートを作成して、それを今後のプロジェクトの開始点として再利用できるようにする場合は、ダウンロードした Simple3DGameDX プロジェクトから GameMain.h
と GameMain.cpp
をコピーして、新しいコア アプリ プロジェクトに追加できます。 これらのファイルを調べて、その内容を学習し、Simple3DGameDX に固有の内容をすべて削除します。 また、コピーしていないコードに依存する部分をコメントにします。 一例として、GameMain.h
は GameRenderer.h
に依存します。 Simple3DGameDX からさらにファイルをコピーすると、コメントを解除できるようになります。
ここでは、テンプレートを作成するときに含めると便利な Simple3DGameDX のいくつかのファイルについて簡単に説明します。 Simple3DGameDX 自体の機能を理解することは、どの場合でも同様に重要です。
ソース ファイル | ファイル フォルダー | 説明 |
---|---|---|
DeviceResources.h/.cpp | Utilities | すべての DirectX デバイス リソースを制御する DeviceResources クラスを定義します。 また、グラフィックス アダプター デバイスが失われたか再作成されたことをアプリケーションに通知するために使用される IDeviceNotify インターフェイスも定義します。 |
DirectXSample.h | Utilities | ConvertDipsToPixels などのヘルパー関数を実装します。 ConvertDipsToPixels は、デバイスに依存しないピクセル (DIP) 単位の長さを物理ピクセル単位の長さに変換します。 |
GameTimer.h/.cpp | Utilities | ゲーム アプリまたは対話型レンダリング アプリで役に立つ、高分解能タイマーを定義します。 |
GameRenderer.h/.cpp | 表示 | 基本的なレンダリング パイプラインを実装する GameRenderer クラスを定義します。 |
GameHud.h/.cpp | 表示 | Direct2D と DirectWrite を使用して、ゲームのヘッドアップ ディスプレイ (HUD) をレンダリングするクラスを定義します。 |
VertexShader.hlsl と VertexShaderFlat.hlsl | シェーダー | 基本的な頂点シェーダー用の上位レベル シェーダー言語 (HLSL) コードが含まれます。 |
PixelShader.hlsl と PixelShaderFlat.hlsl | シェーダー | 基本的なピクセル シェーダー用の上位レベル シェーダー言語 (HLSL) コードが含まれます。 |
ConstantBuffers.hlsli | シェーダー | モデル ビュー プロジェクション (MVP) マトリックスと頂点ごとのデータを頂点シェーダーに渡すために使用される、定数バッファーおよびシェーダー構造体のデータ構造の定義が含まれます。 |
pch.h/.cpp | 該当なし | 共通の C++/WinRT、Windows、DirectX のインクルードが含まれます。 |
次の手順
ここでは、DirectX ゲーム用の新しい UWP プロジェクトを作成し、その内容を確認し、そのプロジェクトをゲーム用に再利用可能なテンプレートに変換する方法を検討しました。 また、Simple3DGameDX サンプル ゲームの重要な部分についても確認しました。
次のセクションは、「ゲームの UWP アプリ フレームワークの定義」です。 そこでは、Simple3DGameDX のしくみについて詳しく見ていきます。