Share via


Marble Maze 範例基礎觀念

本主題說明 Marble Maze 專案的基本特性—例如,它如何在 Windows 執行階段環境中使用 Visual C++、如何建立和結構化,以及如何建置。 本主題也會描述程式碼中使用的數個慣例。

注意

與本文件對應的範例程式碼可以在 DirectX Marble Maze 遊戲範例中找到。

以下是本文件討論規劃及開發通用 Windows 平台 (UWP) 遊戲時所討論的一些重點。

  • 在 Visual Studio 中使用DirectX 11 應用程式 (通用 Windows - C++/CX) 範本來建立您的 DirectX UWP 遊戲。
  • Windows 執行階段會提供類別和介面,讓您能夠以更現代化、面向物件的方式開發 UWP 應用程式。
  • 使用具有山形 (^) 符號的物件參考來管理 Windows 執行階段變數的生命週期,使用 Microsoft::WRL::ComPtr 來管理COM 物件的生命週期,使用 std::shared_ptrstd::unique_ptr 來管理所有其他堆積配置的 C++ 物件的生命週期。
  • 在大部分情況下,請使用例外狀況處理,而不是結果程式碼來處理非預期的錯誤。
  • 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,以取得如何安裝其他元件的相關資訊。

New Project

  1. 選取下一步,然後輸入專案名稱、要儲存的檔案的位置解決方案名稱,然後選取建立

DirectX 11 應用程式 (通用 Windows - C++/CX) 範本中的重要專案設定是 /ZW 選項,它可讓程式使用 Windows 執行階段語言延伸模組。 當您使用 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 連接的裝置進行測試。 然後按一下綠色播放按鈕,以建置並部署至您的裝置。

Debug; x64; Local Machine

控制遊戲

您可以使用觸控、加速計、遊戲控制器或滑鼠來控制 Marble Maze。

  • 使用控制器上的方向鍵來變更使用中的功能表項目。
  • 使用觸控、控制器上的 A 或 [開始] 按鈕,或滑鼠來挑選功能表項目。
  • 使用觸控、加速計、左搖桿或滑鼠來傾斜迷宮。
  • 使用觸控、控制器上的 A 或 [開始] 按鈕,或滑鼠來關閉如高分資料表的功能表。
  • 使用控制器上的 [開始] 按鈕或鍵盤上的 P 鍵來暫停或繼續遊戲。
  • 使用控制器上的 [返回] 按鈕或鍵盤上的 [首頁] 鍵來重新啟動遊戲。
  • 當顯示高分資料表時,請使用控制器上的 [返回] 按鈕或鍵盤上的 [首頁] 鍵來清除所有分數。

程式碼慣例

Windows 執行階段是一個程式設計介面,可用於建立僅在特殊應用程式環境中執行的 UWP 應用程式。 這類應用程式會使用授權的功能、資料類型和裝置,並且從 Microsoft Store 發佈。 在最低層級,Windows 執行階段由應用程式二進位介面 (ABI) 組成。 ABI 是低階二進制合約,可讓多個程式設計語言存取 Windows 執行階段 API,例如 JavaScript、.NET 語言和 Visual C++。

為了從 JavaScript 和 .NET 呼叫 Windows 執行階段 API,這些語言需要每個語言環境特定的投影。 當您從 JavaScript 或 .NET 呼叫 Windows 執行階段 API 時,會叫用投影,進而呼叫基礎 ABI 函式。 雖然您可以直接在 C++ 中呼叫 ABI 函式,但 Microsoft 也會提供 C++ 的投影,因為它們可讓取用 Windows 執行階段 API 變得更簡單,同時仍維持高效能。 Microsoft 也提供 Visual C++ 的語言延伸模組,特別支援 Windows 執行階段投影。 其中許多語言延伸模組類似於 C++/CLI 語言的語法。 不過,原生應用程式會使用此語法以 Windows 執行階段為目標,而不是以 Common Language Runtime (CLR) 為目標。 物件參考或山形符號 (^),修飾詞是這個新語法的重要部分,因為它可透過參考計數來自動刪除執行階段物件。 執行階段不會呼叫 AddRefRelease 等方法來管理 Windows 執行階段物件的生命週期,而是在沒有其他元件參照該物件時 (例如,當它離開範圍或將所有參考設為 nullptr 時) 刪除該物件。 使用 Visual C++ 建立 UWP 應用程式的另一個重要部分是 ref new 關鍵字。 使用 ref new 而不是 new 建立參考計數的 Windows 執行階段物件。 如需詳細資訊,請參閱類型系統 (C++/CX)

重要

您只需在建立 Windows 執行階段物件或建立 Windows 執行階段元件時使用 ^ref new。 當您撰寫不使用 Windows 執行階段的核心應用程式程式碼時,可以使用標準 C++ 語法。

Marble Maze 使用 ^Microsoft::WRL::ComPtr 來管理堆積配置的物件,並最大限度地減少記憶體流失。 我們建議您使用 ^ 來管理 Windows 執行階段變數的生命週期,使用 ComPtr 來管理 COM 變數的生命週期 (例如當您使用DirectX 時),使用 std::shared_ptrstd::unique_ptr 來管理所有其他堆疊配置 C++物件的生命週期。

 

如需 C++ UWP app 可用之語言延伸模組的詳細資訊,請參閱 Visual C++ 語言參考 (C++/CX)

錯誤處理

Marble Maze 會使用例外狀況處理做為處理非預期錯誤的主要方式。 雖然遊戲程式碼傳統上使用記錄或錯誤碼,例如 HRESULT 值來指出錯誤,但例外狀況處理有兩個主要優點。 首先,它可以讓程式碼更容易閱讀和維護。 從程式碼的觀點來看,例外狀況處理是將錯誤傳播至可處理該錯誤的常式更有效率的方式。 使用錯誤碼通常需要每個函式明確地傳播錯誤。 第二個優點是,您可以將 Visual Studio 偵錯工具設定為在發生例外狀況時中斷,以便您立即在錯誤的位置和內容停止。 Windows 執行階段也會大量使用例外狀況處理。 因此,您可以在程式碼中使用例外狀況處理,將所有錯誤處理合併成一個模型。

建議您在錯誤處理模型中使用下列慣例:

  • 使用例外狀況來傳達非預期的錯誤。

  • 請勿使用例外狀況來控制程式碼流程。

  • 只攔截您可以安全地處理及復原的例外狀況。 否則,請勿攔截例外狀況並允許應用程式終止。

  • 當您呼叫傳回 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),您可以標註或描述函式如何使用其參數。 SAL 註釋也會描述傳回值。 SAL 註釋與 C/C++ 程式碼分析工具配合使用,可以發現 C 和 C++ 原始程式碼中可能存在的缺陷。 這個工具所報告的常見程式碼錯誤包括:緩衝區滿溢、未初始化的記憶體、Null 指標取值以及記憶體和資源流失。

考慮 BasicLoader::LoadMesh 方法,該方法在 BasicLoader.h 中宣告。 此方法使用 _In_ 指定 filename 是輸入參數 (因此只能讀取),使用 _Out_ 指定 vertexBufferindexBuffer 是輸出參數 (因此只能寫入),並使用 _Out_opt_ 指定 vertexCountindexCount 是可選的輸出參數 (並且可以寫入)。 由於 vertexCountindexCount 是可選輸出參數,因此允許它們為 nullptr。 C/C++ 程式碼分析工具會檢查對此方法的呼叫,以確保其傳遞的參數符合這些準則。

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 註釋

下一步

閱讀 Marble Maze 應用程式結構,以了解有關 Marble Maze 應用程式程式碼的結構,以及 DirectX UWP 應用程式的結構與傳統桌面應用程式的結構有何不同的資訊。