Bagikan melalui


Struktur aplikasi Marble Maze

Struktur aplikasi DirectX Platform Windows Universal (UWP) berbeda dari aplikasi desktop tradisional. Alih-alih bekerja dengan jenis handel seperti HWND dan fungsi seperti CreateWindow, Windows Runtime menyediakan antarmuka seperti Windows::UI::Core::ICoreWindow sehingga Anda dapat mengembangkan aplikasi UWP dengan cara yang lebih modern dan berorientasi objek. Bagian dokumentasi ini menunjukkan bagaimana kode aplikasi Marble Maze disusun.

Catatan

Kode sampel yang sesuai dengan dokumen ini ditemukan dalam sampel permainan DirectX Marble Maze.

Berikut adalah beberapa poin penting yang dibahas dokumen ini ketika Anda menyusun kode permainan Anda:

  • Dalam fase inisialisasi, siapkan komponen runtime dan pustaka yang digunakan game Anda, dan muat sumber daya khusus game.
  • Aplikasi UWP harus mulai memproses peristiwa dalam waktu 5 detik setelah peluncuran. Oleh karena itu, muat hanya sumber daya penting saat Anda memuat aplikasi Anda. Game harus memuat sumber daya besar di latar belakang dan menampilkan layar kemajuan.
  • Dalam perulangan game, tanggapi peristiwa Windows, baca input pengguna, perbarui objek adegan, dan render adegan.
  • Gunakan penanganan aktivitas untuk merespons peristiwa jendela. (Ini menggantikan pesan jendela dari aplikasi Windows desktop.)
  • Gunakan mesin status untuk mengontrol alur dan urutan logika game.

Organisasi file

Beberapa komponen dalam Marble Maze dapat digunakan kembali dengan permainan apa pun dengan sedikit atau tanpa modifikasi. Untuk permainan Anda sendiri, Anda dapat menyesuaikan organisasi dan ide-ide yang disediakan file-file ini. Tabel berikut ini menjelaskan secara singkat file kode sumber penting.

File Deskripsi
App.h, App.cpp Menentukan kelas App dan DirectXApplicationSource , yang merangkum tampilan (jendela, utas, dan peristiwa) aplikasi.
Audio.h, Audio.cpp Menentukan kelas Audio , yang mengelola sumber daya audio.
BasicLoader.h, BasicLoader.cpp Menentukan kelas BasicLoader , yang menyediakan metode utilitas yang membantu Anda memuat tekstur, jala, dan shader.
BasicMath.h Menentukan struktur dan fungsi yang membantu Anda bekerja dengan data dan komputasi vektor dan matriks. Banyak dari fungsi ini kompatibel dengan jenis shader HLSL.
BasicReaderWriter.h, BasicReaderWriter.cpp Menentukan kelas BasicReaderWriter , yang menggunakan Windows Runtime untuk membaca dan menulis data file di aplikasi UWP.
BasicShapes.h, BasicShapes.cpp Mendefinisikan kelas BasicShapes , yang menyediakan metode utilitas untuk membuat bentuk dasar seperti kubus dan bola. (File-file ini tidak digunakan oleh implementasi Marble Maze).
Camera.h, Camera.cpp Mendefinisikan kelas Kamera , yang menyediakan posisi dan orientasi kamera.
Collision.h, Collision.cpp Mengelola info tabrakan antara marmer dan objek lainnya, seperti labirin.
DDSTextureLoader.h, DDSTextureLoader.cpp Menentukan fungsi CreateDDSTextureFromMemory , yang memuat tekstur yang dalam format .dds dari buffer memori.
DirectXHelper.h Menentukan fungsi pembantu DirectX yang berguna untuk banyak aplikasi DirectX UWP.
LoadScreen.h, LoadScreen.cpp Menentukan kelas LoadScreen , yang menampilkan layar pemuatan selama inisialisasi aplikasi.
MarbleMazeMain.h, MarbleMazeMain.cpp Mendefinisikan kelas MarbleMazeMain , yang mengelola sumber daya khusus game dan mendefinisikan banyak logika game.
MediaStreamer.h, MediaStreamer.cpp Mendefinisikan kelas MediaStreamer , yang menggunakan Media Foundation untuk membantu permainan mengelola sumber daya audio.
PersistentState.h, PersistentState.cpp Menentukan kelas PersistentState , yang membaca dan menulis jenis data primitif dari dan ke penyimpanan cadangan.
Physics.h, Physics.cpp Mendefinisikan kelas Fisika , yang mengimplementasikan simulasi fisika antara marmer dan labirin.
Primitif.h Mendefinisikan jenis geometrik yang digunakan oleh game.
SampleOverlay.h, SampleOverlay.cpp Menentukan kelas SampleOverlay , yang menyediakan data dan operasi 2D dan antarmuka pengguna umum.
SDKMesh.h, SDKMesh.cpp Menentukan kelas SDKMesh , yang memuat dan merender jala yang dalam format SDK Mesh (.sdkmesh).
StepTimer.h Mendefinisikan kelas StepTimer , yang menyediakan cara mudah untuk mendapatkan total dan waktu yang berlalu.
UserInterface.h, UserInterface.cpp Menentukan fungsionalitas yang terkait dengan antarmuka pengguna, seperti sistem menu dan tabel skor tinggi.

 

Format sumber daya waktu desain versus run-time

Ketika Anda bisa, gunakan format run-time alih-alih format waktu desain untuk memuat sumber daya game dengan lebih efisien.

Format waktu desain adalah format yang Anda gunakan saat mendesain sumber daya Anda. Biasanya, desainer 3D bekerja dengan format waktu desain. Beberapa format waktu desain juga berbasis teks sehingga Anda dapat memodifikasinya di editor berbasis teks apa pun. Format waktu desain dapat verbose dan berisi lebih banyak informasi daripada yang dibutuhkan game Anda. Format run-time adalah format biner yang dibaca oleh game Anda. Format run-time biasanya lebih ringkas dan lebih efisien untuk dimuat daripada format waktu desain yang sesuai. Inilah sebabnya mengapa sebagian besar game menggunakan aset run-time pada durasi.

Meskipun game Anda dapat langsung membaca format waktu desain, ada beberapa manfaat untuk menggunakan format run-time terpisah. Karena format run-time sering kali lebih ringkas, format tersebut membutuhkan lebih sedikit ruang disk dan membutuhkan lebih sedikit waktu untuk mentransfer melalui jaringan. Selain itu, format run-time sering direpresentasikan sebagai struktur data yang dipetakan memori. Oleh karena itu, mereka dapat dimuat ke dalam memori jauh lebih cepat daripada, misalnya, file teks berbasis XML. Akhirnya, karena format run-time terpisah biasanya dikodekan biner, format tersebut lebih sulit untuk dimodifikasi oleh pengguna akhir.

Shader HLSL adalah salah satu contoh sumber daya yang menggunakan format waktu desain dan run-time yang berbeda. Marble Maze menggunakan .hlsl sebagai format waktu desain, dan .cso sebagai format run-time. File .hlsl menyimpan kode sumber untuk shader; file .cso menyimpan kode byte shader yang sesuai. Ketika Anda mengonversi file .hlsl offline dan menyediakan file .cso dengan game Anda, Anda menghindari kebutuhan untuk mengonversi file sumber HLSL ke kode byte saat game Anda dimuat.

Untuk alasan instruksional, proyek Marble Maze mencakup format waktu desain dan format run-time untuk banyak sumber daya, tetapi Anda hanya perlu mempertahankan format waktu desain dalam proyek sumber untuk game Anda sendiri karena Anda dapat mengonversinya ke format run-time saat Anda membutuhkannya. Dokumentasi ini memperlihatkan cara mengonversi format waktu desain ke format run-time.

Siklus hidup aplikasi

Marble Maze mengikuti siklus hidup aplikasi UWP yang khas. Untuk informasi selengkapnya tentang siklus hidup aplikasi UWP, lihat Siklus hidup aplikasi.

Ketika game UWP menginisialisasi, biasanya menginisialisasi komponen runtime seperti Direct3D, Direct2D, dan pustaka input, audio, atau fisika apa pun yang digunakannya. Ini juga memuat sumber daya khusus game yang diperlukan sebelum permainan dimulai. Inisialisasi ini terjadi satu kali selama sesi permainan.

Setelah inisialisasi, game biasanya menjalankan perulangan game. Dalam perulangan ini, game biasanya melakukan empat tindakan: memproses peristiwa Windows, mengumpulkan input, memperbarui objek adegan, dan merender adegan. Ketika game memperbarui adegan, game dapat menerapkan status input saat ini ke objek adegan dan mensimulasikan peristiwa fisik, seperti tabrakan objek. Permainan ini juga dapat melakukan aktivitas lain seperti bermain efek suara atau mengirim data melalui jaringan. Ketika permainan merender adegan, ia menangkap status adegan saat ini dan menariknya ke perangkat tampilan. Bagian berikut menjelaskan aktivitas ini secara lebih rinci.

Menambahkan ke templat

Templat Aplikasi DirectX 11 (Universal Windows) membuat jendela inti yang dapat Anda render dengan Direct3D. Templat ini juga menyertakan kelas DeviceResources yang membuat semua sumber daya perangkat Direct3D yang diperlukan untuk merender konten 3D di aplikasi UWP.

Kelas Aplikasi membuat objek kelas MarbleMazeMain , memulai pemuatan sumber daya, perulangan untuk memperbarui timer, dan memanggil metode MarbleMazeMain::Render setiap bingkai. Metode App::OnWindowSizeChanged, App::OnDpiChanged, dan App::OnOrientationChanged masing-masing memanggil metode MarbleMazeMain::CreateWindowSizeDependentResources , dan metode App::Run memanggil metode MarbleMazeMain::Update dan MarbleMazeMain::Render .

Contoh berikut menunjukkan di mana metode App::SetWindow membuat objek kelas MarbleMazeMain . Kelas DeviceResources diteruskan ke metode sehingga dapat menggunakan objek Direct3D untuk penyajian.

    m_main = std::unique_ptr<MarbleMazeMain>(new MarbleMazeMain(m_deviceResources));

Kelas Aplikasi juga mulai memuat sumber daya yang ditangguhkan untuk game. Lihat bagian berikutnya untuk detail selengkapnya.

Selain itu, kelas Aplikasi menyiapkan penanganan aktivitas untuk peristiwa CoreWindow . Ketika handler untuk peristiwa ini dipanggil, mereka meneruskan input ke kelas MarbleMazeMain .

Memuat aset game di latar belakang

Untuk memastikan bahwa game Anda dapat merespons peristiwa jendela dalam waktu 5 detik setelah diluncurkan, kami sarankan Anda memuat aset game Anda secara asinkron, atau di latar belakang. Saat aset dimuat di latar belakang, game Anda dapat merespons peristiwa jendela.

Catatan

Anda juga dapat menampilkan menu utama saat siap, dan memungkinkan aset yang tersisa untuk terus memuat di latar belakang. Jika pengguna memilih opsi dari menu sebelum semua sumber daya dimuat, Anda dapat menunjukkan bahwa sumber daya adegan terus dimuat dengan menampilkan bilah kemajuan, misalnya.

 

Bahkan jika game Anda berisi aset game yang relatif sedikit, ada baiknya untuk memuatnya secara asinkron karena dua alasan. Salah satu alasannya adalah sulit untuk menjamin bahwa semua sumber daya Anda akan dimuat dengan cepat di semua perangkat dan semua konfigurasi. Selain itu, dengan menggabungkan pemuatan asinkron lebih awal, kode Anda siap untuk diskalakan saat Anda menambahkan fungsionalitas.

Pemuatan aset asinkron dimulai dengan metode App::Load . Metode ini menggunakan kelas tugas untuk memuat aset game di latar belakang.

    task<void>([=]()
    {
        m_main->LoadDeferredResources(true, false);
    });

Kelas MarbleMazeMain mendefinisikan bendera m_deferredResourcesReady untuk menunjukkan bahwa pemuatan asinkron selesai. Metode MarbleMazeMain::LoadDeferredResources memuat sumber daya game lalu mengatur bendera ini. Fase pembaruan (MarbleMazeMain::Update) dan render (MarbleMazeMain::Render) aplikasi memeriksa bendera ini. Ketika bendera ini diatur, permainan berlanjut seperti biasa. Jika bendera belum diatur, game akan menampilkan layar pemuatan.

Untuk informasi selengkapnya tentang pemrograman asinkron untuk aplikasi UWP, lihat Pemrograman asinkron di C++.

Tip

Jika Anda menulis kode game yang merupakan bagian dari Pustaka C++ Runtime Windows (dengan kata lain, DLL), pertimbangkan apakah akan membaca Membuat Operasi Asinkron di C++ untuk aplikasi UWP untuk mempelajari cara membuat operasi asinkron yang dapat digunakan oleh aplikasi dan pustaka lainnya.

 

Perulangan permainan

Metode App::Run menjalankan perulangan game utama (MarbleMazeMain::Update). Metode ini disebut setiap bingkai.

Untuk membantu memisahkan tampilan dan kode jendela dari kode khusus game, kami menerapkan metode App::Run untuk meneruskan pembaruan dan merender panggilan ke objek MarbleMazeMain .

Contoh berikut menunjukkan metode App::Run , yang mencakup perulangan game utama. Perulangan game memperbarui total variabel waktu dan kerangka waktu, lalu memperbarui dan merender adegan. Ini juga memastikan bahwa konten hanya dirender saat jendela terlihat.

void App::Run()
{
    while (!m_windowClosed)
    {
        if (m_windowVisible)
        {
            CoreWindow::GetForCurrentThread()->Dispatcher->
                ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

            m_main->Update();

            if (m_main->Render())
            {
                m_deviceResources->Present();
            }
        }
        else
        {
            CoreWindow::GetForCurrentThread()->Dispatcher->
                ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
        }
    }

    // The app is exiting so do the same thing as if the app were being suspended.
    m_main->OnSuspending();

#ifdef _DEBUG
    // Dump debug info when exiting.
    DumpD3DDebug();
#endif //_DEGBUG
}

Mesin status

Game biasanya berisi mesin status (juga dikenal sebagai mesin status terbatas, atau FSM) untuk mengontrol alur dan urutan logika game. Komputer status berisi sejumlah status tertentu dan kemampuan untuk transisi di antara mereka. Komputer status biasanya dimulai dari status awal , transisi ke satu atau beberapa status perantara , dan mungkin berakhir pada status terminal .

Perulangan game sering menggunakan mesin status sehingga dapat melakukan logika yang khusus untuk status permainan saat ini. Marble Maze mendefinisikan enumerasi GameState , yang mendefinisikan setiap kemungkinan status permainan.

enum class GameState
{
    Initial,
    MainMenu,
    HighScoreDisplay,
    PreGameCountdown,
    InGameActive,
    InGamePaused,
    PostGameResults,
};

Status MainMenu , misalnya, mendefinisikan bahwa menu utama muncul, dan bahwa game tidak aktif. Sebaliknya, status InGameActive mendefinisikan bahwa game aktif, dan bahwa menu tidak muncul. Kelas MarbleMazeMain mendefinisikan variabel anggota m_gameState untuk menahan status permainan aktif.

Metode MarbleMazeMain::Update dan MarbleMazeMain::Render menggunakan pernyataan switch untuk melakukan logika untuk status saat ini. Contoh berikut menunjukkan seperti apa pernyataan pengalihan untuk metode MarbleMazeMain::Update (detail dihapus untuk mengilustrasikan struktur).

switch (m_gameState)
{
case GameState::MainMenu:
    // Do something with the main menu. 
    break;

case GameState::HighScoreDisplay:
    // Do something with the high-score table. 
    break;

case GameState::PostGameResults:
    // Do something with the game results. 
    break;

case GameState::InGamePaused:
    // Handle the paused state. 
    break;
}

Ketika logika atau penyajian game tergantung pada status permainan tertentu, kami menekankannya dalam dokumentasi ini.

Menangani peristiwa aplikasi dan jendela

Windows Runtime menyediakan sistem penanganan peristiwa berorientasi objek sehingga Anda dapat mengelola pesan Windows dengan lebih mudah. Untuk menggunakan peristiwa dalam aplikasi, Anda harus menyediakan penanganan aktivitas, atau metode penanganan peristiwa, yang merespons peristiwa tersebut. Anda juga harus mendaftarkan penanganan aktivitas dengan sumber kejadian. Proses ini sering disebut sebagai kabel peristiwa.

Mendukung penangguhan, lanjutkan, dan mulai ulang

Marble Maze ditangguhkan ketika pengguna beralih menjauh darinya atau ketika Windows memasuki status daya rendah. Permainan dilanjutkan ketika pengguna memindahkannya ke latar depan atau ketika Windows keluar dari status daya rendah. Umumnya, Anda tidak menutup aplikasi. Windows dapat menghentikan aplikasi saat dalam status ditangguhkan dan Windows memerlukan sumber daya, seperti memori, yang digunakan aplikasi. Windows memberi tahu aplikasi saat akan ditangguhkan atau dilanjutkan, tetapi tidak memberi tahu aplikasi saat akan dihentikan. Oleh karena itu, aplikasi Anda harus dapat menyimpan—pada saat Windows memberi tahu aplikasi Anda bahwa aplikasi tersebut akan ditangguhkan—data apa pun yang akan diperlukan untuk memulihkan status pengguna saat ini saat aplikasi dimulai ulang. Jika aplikasi Anda memiliki status pengguna signifikan yang mahal untuk disimpan, Anda mungkin juga perlu menyimpan status secara teratur, bahkan sebelum aplikasi Anda menerima pemberitahuan penangguhan. Marble Maze merespons menangguhkan dan melanjutkan pemberitahuan karena dua alasan:

  1. Ketika aplikasi ditangguhkan, game menyimpan status permainan saat ini dan menjeda pemutaran audio. Saat aplikasi dilanjutkan, game melanjutkan pemutaran audio.
  2. Ketika aplikasi ditutup dan kemudian dimulai ulang, game dilanjutkan dari status sebelumnya.

Marble Maze melakukan tugas-tugas berikut untuk mendukung penangguhan dan melanjutkan:

  • Ini menyimpan statusnya ke penyimpanan persisten di titik-titik utama dalam game, seperti ketika pengguna mencapai titik pemeriksaan.
  • Ini menanggapi pemberitahuan yang ditangguhkan dengan menyimpan statusnya ke penyimpanan persisten.
  • Ini merespons untuk melanjutkan pemberitahuan dengan memuat statusnya dari penyimpanan persisten. Ini juga memuat status sebelumnya selama startup.

Untuk mendukung penangguhan dan lanjutkan, Marble Maze mendefinisikan kelas PersistentState . (Lihat PersistentState.h dan PersistentState.cpp). Kelas ini menggunakan antarmuka Windows::Foundation::Collections::IPropertySet untuk membaca dan menulis properti. Kelas PersistentState menyediakan metode yang membaca dan menulis jenis data primitif (seperti bool, int, float, XMFLOAT3, dan Platform::String), dari dan ke penyimpanan backing.

ref class PersistentState
{
internal:
    void Initialize(
        _In_ Windows::Foundation::Collections::IPropertySet^ settingsValues,
        _In_ Platform::String^ key
        );

    void SaveBool(Platform::String^ key, bool value);
    void SaveInt32(Platform::String^ key, int value);
    void SaveSingle(Platform::String^ key, float value);
    void SaveXMFLOAT3(Platform::String^ key, DirectX::XMFLOAT3 value);
    void SaveString(Platform::String^ key, Platform::String^ string);

    bool LoadBool(Platform::String^ key, bool defaultValue);
    int  LoadInt32(Platform::String^ key, int defaultValue);
    float LoadSingle(Platform::String^ key, float defaultValue);

    DirectX::XMFLOAT3 LoadXMFLOAT3(
        Platform::String^ key, 
        DirectX::XMFLOAT3 defaultValue);

    Platform::String^ LoadString(
        Platform::String^ key, 
        Platform::String^ defaultValue);

private:
    Platform::String^ m_keyName;
    Windows::Foundation::Collections::IPropertySet^ m_settingsValues;
};

Kelas MarbleMazeMain menyimpan objek PersistentState . Konstruktor MarbleMazeMain menginisialisasi objek ini dan menyediakan penyimpanan data aplikasi lokal sebagai penyimpanan data cadangan.

m_persistentState = ref new PersistentState();

m_persistentState->Initialize(
    Windows::Storage::ApplicationData::Current->LocalSettings->Values,
    "MarbleMaze");

Marble Maze menyimpan keadaannya ketika marmer melewati titik pemeriksaan atau tujuan (dalam metode MarbleMazeMain::Update ), dan ketika jendela kehilangan fokus (dalam metode MarbleMazeMain::OnFocusChange ). Jika game Anda menyimpan sejumlah besar data status, kami sarankan Anda sesekali menyimpan status ke penyimpanan persisten dengan cara yang sama karena Anda hanya memiliki beberapa detik untuk menanggapi pemberitahuan yang ditangguhkan. Oleh karena itu, saat aplikasi Anda menerima pemberitahuan penangguhan, aplikasi hanya perlu menyimpan data status yang telah berubah.

Untuk menanggapi pemberitahuan penangguhan dan melanjutkan, kelas MarbleMazeMain menentukan metode SaveState dan LoadState yang dipanggil saat ditangguhkan dan dilanjutkan. Metode MarbleMazeMain::OnSuspending menangani peristiwa yang ditangguhkan dan metode MarbleMazeMain::OnResuming menangani peristiwa resume.

Metode MarbleMazeMain::OnSuspending menyimpan status permainan dan menangguhkan audio.

void MarbleMazeMain::OnSuspending()
{
    SaveState();
    m_audio.SuspendAudio();
}

Metode MarbleMazeMain::SaveState menyimpan nilai status permainan seperti posisi dan kecepatan marmer saat ini, titik pemeriksaan terbaru, dan tabel skor tinggi.

void MarbleMazeMain::SaveState()
{
    m_persistentState->SaveXMFLOAT3(":Position", m_physics.GetPosition());
    m_persistentState->SaveXMFLOAT3(":Velocity", m_physics.GetVelocity());

    m_persistentState->SaveSingle(
        ":ElapsedTime", 
        m_inGameStopwatchTimer.GetElapsedTime());

    m_persistentState->SaveInt32(":GameState", static_cast<int>(m_gameState));
    m_persistentState->SaveInt32(":Checkpoint", static_cast<int>(m_currentCheckpoint));

    int i = 0;
    HighScoreEntries entries = m_highScoreTable.GetEntries();
    const int bufferLength = 16;
    char16 str[bufferLength];

    m_persistentState->SaveInt32(":ScoreCount", static_cast<int>(entries.size()));

    for (auto iter = entries.begin(); iter != entries.end(); ++iter)
    {
        int len = swprintf_s(str, bufferLength, L"%d", i++);
        Platform::String^ string = ref new Platform::String(str, len);

        m_persistentState->SaveSingle(
            Platform::String::Concat(":ScoreTime", string), 
            iter->elapsedTime);

        m_persistentState->SaveString(
            Platform::String::Concat(":ScoreTag", string), 
            iter->tag);
    }
}

Ketika permainan dilanjutkan, itu hanya harus melanjutkan audio. Ini tidak harus memuat status dari penyimpanan persisten karena status sudah dimuat dalam memori.

Bagaimana permainan menangguhkan dan melanjutkan audio dijelaskan dalam dokumen Menambahkan audio ke sampel Marble Maze.

Untuk mendukung mulai ulang, konstruktor MarbleMazeMain , yang dipanggil selama startup, memanggil metode MarbleMazeMain::LoadState . Metode MarbleMazeMain::LoadState membaca dan menerapkan status ke objek game. Metode ini juga mengatur status permainan saat ini untuk dijeda jika permainan dijeda atau aktif ketika ditangguhkan. Kami menjeda game agar pengguna tidak terkejut dengan aktivitas yang tidak terduga. Ini juga bergerak ke menu utama jika permainan tidak dalam keadaan gameplay ketika ditangguhkan.

void MarbleMazeMain::LoadState()
{
    XMFLOAT3 position = m_persistentState->LoadXMFLOAT3(
        ":Position", 
        m_physics.GetPosition());

    XMFLOAT3 velocity = m_persistentState->LoadXMFLOAT3(
        ":Velocity", 
        m_physics.GetVelocity());

    float elapsedTime = m_persistentState->LoadSingle(":ElapsedTime", 0.0f);

    int gameState = m_persistentState->LoadInt32(
        ":GameState", 
        static_cast<int>(m_gameState));

    int currentCheckpoint = m_persistentState->LoadInt32(
        ":Checkpoint", 
        static_cast<int>(m_currentCheckpoint));

    switch (static_cast<GameState>(gameState))
    {
    case GameState::Initial:
        break;

    case GameState::MainMenu:
    case GameState::HighScoreDisplay:
    case GameState::PreGameCountdown:
    case GameState::PostGameResults:
        SetGameState(GameState::MainMenu);
        break;

    case GameState::InGameActive:
    case GameState::InGamePaused:
        m_inGameStopwatchTimer.SetVisible(true);
        m_inGameStopwatchTimer.SetElapsedTime(elapsedTime);
        m_physics.SetPosition(position);
        m_physics.SetVelocity(velocity);
        m_currentCheckpoint = currentCheckpoint;
        SetGameState(GameState::InGamePaused);
        break;
    }

    int count = m_persistentState->LoadInt32(":ScoreCount", 0);

    const int bufferLength = 16;
    char16 str[bufferLength];

    for (int i = 0; i < count; i++)
    {
        HighScoreEntry entry;
        int len = swprintf_s(str, bufferLength, L"%d", i);
        Platform::String^ string = ref new Platform::String(str, len);

        entry.elapsedTime = m_persistentState->LoadSingle(
            Platform::String::Concat(":ScoreTime", string), 
            0.0f);

        entry.tag = m_persistentState->LoadString(
            Platform::String::Concat(":ScoreTag", string), 
            L"");

        m_highScoreTable.AddScoreToTable(entry);
    }
}

Penting

Marble Maze tidak membedakan antara awal yang dingin—yaitu, dimulai untuk pertama kalinya tanpa peristiwa penangguhan sebelumnya—dan melanjutkan dari status ditangguhkan. Ini adalah desain yang direkomendasikan untuk semua aplikasi UWP.

Untuk informasi selengkapnya tentang data aplikasi, lihat Menyimpan dan mengambil pengaturan dan data aplikasi lainnya.

Langkah berikutnya

Baca Menambahkan konten visual ke sampel Marble Maze untuk informasi tentang beberapa praktik utama yang perlu diingat saat Anda bekerja dengan sumber daya visual.