Marble Maze-toepassingsstructuur

De structuur van een UWP-app (DirectX Universal Windows Platform) verschilt van die van een traditionele bureaubladtoepassing. In plaats van te werken met handletypen zoals HWND- en functies zoals CreateWindow-, biedt de Windows Runtime interfaces zoals Windows::UI::Core::ICoreWindow, zodat u UWP-apps op een modernere, objectgeoriënteerde manier kunt ontwikkelen. In deze sectie van de documentatie ziet u hoe de code van de Marble Maze-app is gestructureerd.

Opmerking

De voorbeeldcode die overeenkomt met dit document vindt u in het DirectX Marble Maze-gamevoorbeeld.

Hier volgen enkele belangrijke punten die in dit document worden besproken bij het structureren van uw gamecode:

  • Stel in de initialisatiefase de runtime- en bibliotheekonderdelen in die door uw game worden gebruikt en laad gamespecifieke resources.
  • UWP-apps moeten binnen 5 seconden na het starten beginnen met het verwerken van gebeurtenissen. Laad daarom alleen essentiële resources wanneer u uw app laadt. Games moeten grote resources op de achtergrond laden en een voortgangsscherm weergeven.
  • Reageer in de gamelus op Windows-gebeurtenissen, lees gebruikersinvoer, werk scèneobjecten bij en geef de scène weer.
  • Gebruik gebeurtenis-handlers om te reageren op venster-gebeurtenissen. (Deze vervangen de vensterberichten van Windows-toepassingen op het bureaublad.)
  • Gebruik een statusmachine om de stroom en volgorde van de gamelogica te beheren.

Bestandsorganisatie

Sommige van de onderdelen in Marble Maze kunnen opnieuw worden gebruikt met elk spel met weinig of geen wijziging. Voor uw eigen spel kunt u de organisatie en ideeën aanpassen die deze bestanden bieden. In de volgende tabel worden de belangrijke broncodebestanden kort beschreven.

Bestanden Beschrijving
App.h, App.cpp Hiermee definieert u de App- en DirectXApplicationSource klassen, die de weergave (venster, thread en gebeurtenissen) van de app inkapselen.
Audio.h, Audio.cpp Hiermee definieert u de klasse Audio, waarmee audiobronnen worden beheerd.
BasicLoader.h, BasicLoader.cpp Definieert de BasicLoader klasse, die hulpprogrammamethoden biedt waarmee u patronen, meshes en shaders kunt laden.
BasicMath.h Definieert structuren en functies die u helpen bij het werken met vector- en matrixgegevens en -berekeningen. Veel van deze functies zijn compatibel met HLSL-shadertypen.
BasicReaderWriter.h, BasicReaderWriter.cpp Hiermee definieert u de klasse BasicReaderWriter, die de Windows Runtime gebruikt voor het lezen en schrijven van bestandsgegevens in een UWP-app.
BasicShapes.h, BasicShapes.cpp Definieert de BasicShapes klasse, die hulpprogrammamethoden biedt voor het maken van basisshapes, zoals kubussen en bollen. (Deze bestanden worden niet gebruikt door de Marble Maze-implementatie).
Camera.h, Camera.cpp Definieert de Camera klasse, die de positie en stand van een camera biedt.
Botsing.h, Collision.cpp Beheert botsingsgegevens tussen de marmeren en andere objecten, zoals het doolhof.
DDSTextureLoader.h, DDSTextureLoader.cpp Hiermee definieert u de functie CreateDDSTextureFromMemory, waarmee patronen worden geladen die zich in .dds indeling bevinden vanuit een geheugenbuffer.
DirectXHelper.h Definieert DirectX-helperfuncties die nuttig zijn voor veel DirectX UWP-apps.
LoadScreen.h, LoadScreen.cpp Definieert de LoadScreen--klasse, waarin een laadscherm wordt weergegeven tijdens de initialisatie van de app.
MarbleMazeMain.h, MarbleMazeMain.cpp Definieert de MarbleMazeMain klasse, waarmee gamespecifieke resources worden beheerd en veel van de gamelogica wordt gedefinieerd.
MediaStreamer.h, MediaStreamer.cpp Definieert de MediaStreamer klasse, die gebruikmaakt van Media Foundation om het spel te helpen bij het beheren van audiobronnen.
PersistentState.h, PersistentState.cpp Definieert de PersistentState--klasse, die primitieve gegevenstypen leest en schrijft van en naar een back-uparchief.
Natuurkunde.h, Physics.cpp Definieert de fysica klasse, waarmee de fysicasimulatie tussen het marmer en het doolhof wordt geïmplementeerd.
Primitieven.h Definieert geometrische typen die door het spel worden gebruikt.
SampleOverlay.h, SampleOverlay.cpp Definieert de SampleOverlay--klasse, die algemene 2D- en gebruikersinterfacegegevens en -bewerkingen biedt.
SDKMesh.h, SDKMesh.cpp Definieert de SDKMesh-klasse, die meshes laadt en weergeeft die in het SDK Mesh-formaat (.sdkmesh) staan.
StepTimer.h Hiermee definieert u de StepTimer-klasse, die een eenvoudige manier biedt om het totaal en de verstreken tijden op te halen.
UserInterface.h, UserInterface.cpp Definieert functionaliteit die betrekking heeft op de gebruikersinterface, zoals het menusysteem en de tabel met hoge score.

 

Ontwerptijd versus runtime-resourceindelingen

Wanneer u dat kunt, kunt u runtime-indelingen gebruiken in plaats van ontwerptijdindelingen om gameresources efficiënter te laden.

Een ontwerpfase formaat is het formaat dat u gebruikt wanneer u uw resource ontwerpt. Normaal gesproken werken 3D-ontwerpers met ontwerptijdformaten. Sommige indelingen voor ontwerptijd zijn ook tekstgebaseert, zodat u deze in elke teksteditor kunt wijzigen. Ontwerptijd-indelingen kunnen uitgebreid zijn en bevatten meer informatie dan uw game vereist. Een run-time-formaat is het binaire formaat dat door uw game gelezen wordt. Runtime-indelingen zijn doorgaans compacter en efficiënter om te laden dan de bijbehorende indelingen voor ontwerptijd. Daarom gebruiken de meeste games runtimeactiva tijdens runtime.

Hoewel uw game direct een ontwerpformaat kan lezen, zijn er verschillende voordelen aan het gebruik van een afzonderlijk runtime-formaat. Omdat runtime-indelingen vaak compacter zijn, is er minder schijfruimte nodig en is er minder tijd nodig om over te dragen via een netwerk. Runtime-indelingen worden ook vaak weergegeven als gegevensstructuren die zijn toegewezen aan het geheugen. Daarom kunnen ze veel sneller in het geheugen worden geladen dan bijvoorbeeld een XML-tekstbestand. Ten slotte, omdat afzonderlijke runtime-indelingen doorgaans binair zijn gecodeerd, zijn ze moeilijker voor de eindgebruiker om te wijzigen.

HLSL-shaders zijn een voorbeeld van resources die verschillende ontwerp- en runtime-indelingen gebruiken. Marble Maze gebruikt .hlsl als het ontwerptijdformaat en .cso als het uitvoeringstijdformaat. Een HLSL-bestand bevat broncode voor de shader; een .cso-bestand bevat de bijbehorende shader byte-code. Wanneer u HLSL-bestanden offline converteert en cso-bestanden met uw game opgeeft, hoeft u geen HLSL-bronbestanden te converteren naar bytecode wanneer uw game wordt geladen.

Voor instructiedoeleinden bevat het Marble Maze-project zowel de ontwerpformaat als het runtimeformaat voor veel bronnen, maar u hoeft alleen de ontwerpformaten in het bronproject voor uw eigen spel te behouden, omdat u ze kunt converteren naar runtimeformaten wanneer u ze nodig hebt. In deze documentatie ziet u hoe u de indelingen voor ontwerptijd converteert naar de runtime-indelingen.

Levenscyclus van toepassingen

Marble Maze volgt de levenscyclus van een typische UWP-app. Zie App-levenscyclusvoor meer informatie over de levenscyclus van een UWP-app.

Wanneer een UWP-game initialiseert, initialiseert het doorgaans runtime-onderdelen zoals Direct3D, Direct2D en invoer-, audio- of fysicabibliotheken die worden gebruikt. Het laadt ook gamespecifieke resources die vereist zijn voordat het spel begint. Deze initialisatie vindt eenmalig plaats tijdens een gamesessie.

Na de initialisering voeren games meestal de game-lusuit. In deze lus voeren games doorgaans vier acties uit: Windows-gebeurtenissen verwerken, invoer verzamelen, scèneobjecten bijwerken en de scène weergeven. Wanneer de game de scène bijwerkt, kan deze de huidige invoerstatus toepassen op de scèneobjecten en fysieke gebeurtenissen simuleren, zoals botsingen. Het spel kan ook andere activiteiten uitvoeren, zoals het afspelen van geluidseffecten of het verzenden van gegevens via het netwerk. Wanneer het spel de scène weergeeft, wordt de huidige staat van de scène vastgelegd en op het weergaveapparaat weergegeven. In de volgende secties worden deze activiteiten gedetailleerder beschreven.

Toevoegen aan de sjabloon

Met de DirectX 11-app (Universal Windows) sjabloon wordt een kernvenster gemaakt dat u met Direct3D kunt weergeven. De sjabloon bevat ook de DeviceResources-klasse waarmee alle Direct3D-apparaatresources worden gemaakt die nodig zijn voor het weergeven van 3D-inhoud in een UWP-app.

De App--klasse maakt het MarbleMazeMain klasseobject, start het laden van resources en voert een lus uit om de timer bij te werken, en roept de methode MarbleMazeMain::Render bij elk frame aan. De methoden App::OnWindowSizeChanged, App::OnDpiChangeden App::OnOrientationChanged roepen elk de methode MarbleMazeMain::CreateWindowSizeDependentResources aan, en de methode App::Run roept de methoden MarbleMazeMain::Update en MarbleMazeMain::Render aan.

In het volgende voorbeeld ziet u waar de methode App::SetWindow het MarbleMazeMain klasseobject maakt. De klasse DeviceResources wordt doorgegeven aan de methode, zodat de Direct3D-objecten kunnen worden gebruikt voor rendering.

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

De App-klasse begint ook met het laden van de uitgestelde resources voor de game. Zie de volgende sectie voor meer informatie.

Daarnaast stelt de klasse App de eventhandlers in voor de CoreWindow-gebeurtenissen. Wanneer de handlers voor deze gebeurtenissen worden aangeroepen, geven ze de invoer door aan de klasse MarbleMazeMain.

Spelmaterialen op de achtergrond laden

Om ervoor te zorgen dat uw game binnen 5 seconden kan reageren op vensterevenementen nadat deze is gestart, raden we u aan om uw gameactiva asynchroon of op de achtergrond te laden. Wanneer assets op de achtergrond worden geladen, kan uw game reageren op vensterevenementen.

Opmerking

U kunt ook het hoofdmenu weergeven wanneer het klaar is en de resterende assets toestaan om op de achtergrond te blijven laden. Als de gebruiker een optie selecteert in het menu voordat alle resources worden geladen, kunt u aangeven dat scènebronnen blijven laden door bijvoorbeeld een voortgangsbalk weer te geven.

 

Zelfs als uw game relatief weinig spelassets bevat, is het raadzaam om ze asynchroon te laden om twee redenen. Een van de redenen is dat het moeilijk is om te garanderen dat al uw resources snel worden geladen op alle apparaten en alle configuraties. Door asynchroon laden vroeg op te nemen, is uw code ook klaar om te schalen wanneer u functionaliteit toevoegt.

Asynchroon laden van activa begint met de methode App::Load. Deze methode maakt gebruik van de taak klasse om game-assets op de achtergrond te laden.

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

De klasse MarbleMazeMain definieert de m_deferredResourcesReady vlag om aan te geven dat asynchroon laden is voltooid. De MarbleMazeMain::LoadDeferredResources methode laadt de gameresources en stelt deze vlag in. De update (MarbleMazeMain::Update) en renderfasen (MarbleMazeMain::Render) van de app controleren deze vlag. Wanneer deze vlag is ingesteld, gaat het spel verder als normaal. Als de vlag nog niet is ingesteld, wordt in het spel het laadscherm weergegeven.

Zie Asynchrone programmering in C++voor meer informatie over asynchrone programmering voor UWP-apps.

Aanbeveling

Als u gamecode schrijft die deel uitmaakt van een Windows Runtime C++-bibliotheek (met andere woorden, een DLL), overweeg dan om Asynchrone bewerkingen in C++ voor UWP-apps te lezen voor meer informatie over het maken van asynchrone bewerkingen die kunnen worden gebruikt door apps en andere bibliotheken.

 

De gameloop

Met de methode App::Run wordt de hoofdspellus (MarbleMazeMain::Update) uitgevoerd. Deze methode wordt elk frame genoemd.

Om weergave- en venstercode van gamespecifieke code te scheiden, hebben we de methode App::Run geïmplementeerd om update- en renderoproepen door te sturen naar het MarbleMazeMain-object.

In het volgende voorbeeld ziet u de methode App::Run, die de hoofdspellus bevat. De gamelus werkt de totale tijd- en frametijdvariabelen bij en werkt vervolgens de scène bij en geeft deze weer. Dit zorgt er ook voor dat inhoud alleen wordt weergegeven wanneer het venster zichtbaar is.

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
}

De toestandsmachine

Games bevatten doorgaans een statusmachine (ook wel bekend als een eindige statusmachineof FSM) om de stroom en volgorde van de gamelogica te beheren. Een statusmachine bevat een bepaald aantal statussen en de mogelijkheid om ertussen over te stappen. Een statusmachine begint meestal vanaf een initiële status van, gaat over naar een of meer tussenliggende statussen en eindigt mogelijk op een terminal status.

Een gamelus maakt vaak gebruik van een statusmachine, zodat deze de logica kan uitvoeren die specifiek is voor de huidige gamestatus. Marble Maze definieert de GameState opsomming, die elke mogelijke status van het spel definieert.

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

De MainMenu toestand definieert bijvoorbeeld dat het hoofdmenu verschijnt en dat het spel niet actief is. Omgekeerd bepaalt de status InGameActive dat het spel actief is en dat het menu niet wordt weergegeven. De klasse MarbleMazeMain definieert de m_gameState lidvariabele voor de actieve gamestatus.

De MarbleMazeMain::Update en MarbleMazeMain::Render methoden gebruiken schakelinstructies om logica voor de huidige status uit te voeren. In het volgende voorbeeld ziet u hoe een switch-instructie eruit kan zien voor de methode MarbleMazeMain::Update (details worden verwijderd om de structuur te illustreren).

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;
}

Wanneer gamelogica of rendering afhankelijk is van een specifieke gamestatus, benadrukken we dit in deze documentatie.

App- en venster-gebeurtenissen verwerken

De Windows Runtime biedt een objectgeoriënteerd systeem voor gebeurtenisafhandeling, zodat u Windows-berichten eenvoudiger kunt beheren. Als u een gebeurtenis in een toepassing wilt gebruiken, moet u een gebeurtenis-handler of gebeurtenisafhandelingsmethode opgeven die reageert op de gebeurtenis. U moet ook de gebeurtenis-handler registreren bij de gebeurtenisbron. Dit proces wordt vaak eventkoppeling genoemd.

Ondersteuning voor onderbreken, hervatten en opnieuw opstarten

Marble Maze wordt onderbroken wanneer de gebruiker ervan afschakelt of wanneer Windows een lage energiestatus krijgt. Het spel wordt hervat wanneer de gebruiker het verplaatst naar de voorgrond of wanneer Windows uit een lage energiestatus komt. Over het algemeen sluit u geen apps. Windows kan de app afsluiten wanneer deze zich in de geschorste toestand bevindt en wanneer Windows de resources, zoals geheugen, nodig heeft die de app gebruikt. Windows waarschuwt een app wanneer deze op het punt staat te worden onderbroken of hervat, maar de app wordt niet gewaarschuwd wanneer deze wordt beëindigd. Daarom moet uw app in staat zijn om, wanneer Windows uw app waarschuwt dat deze op het punt staat te worden onderbroken, alle gegevens op te slaan die nodig zijn om de huidige gebruikersstatus te herstellen wanneer de app opnieuw wordt opgestart. Als uw app belangrijke gebruikersgegevens heeft die kostbaar zijn om op te slaan, moet u mogelijk ook regelmatig de status opslaan, zelfs voordat uw app de melding voor onderbreken ontvangt. Marble Maze reageert om twee redenen op het onderbreken en hervatten van meldingen:

  1. Wanneer de app is onderbroken, wordt de huidige gamestatus opgeslagen en wordt het afspelen van audio onderbroken. Wanneer de app wordt hervat, wordt het afspelen van audio hervat.
  2. Wanneer de app wordt gesloten en later opnieuw wordt opgestart, wordt de game hervat vanaf de vorige status.

Marble Maze voert de volgende taken uit ter ondersteuning van onderbreken en hervatten:

  • De status wordt opgeslagen in permanente opslag op belangrijke punten in het spel, bijvoorbeeld wanneer de gebruiker een controlepunt bereikt.
  • Het reageert op het onderbreken van meldingen door de status op te slaan in permanente opslag.
  • Het reageert op hervattingsmeldingen door zijn staat vanuit permanente opslag te laden. Tijdens het opstarten wordt ook de vorige status geladen.

Marble Maze definieert de klasse PersistentState ter ondersteuning van onderbreken en hervatten. (Zie PersistentState.h en PersistentState.cpp). Deze klasse maakt gebruik van de Windows::Foundation::Collections::IPropertySet interface voor het lezen en schrijven van eigenschappen. De klasse PersistentState biedt methoden voor het lezen en schrijven van primitieve gegevenstypen (zoals bool, int, float-, XMFLOAT3en Platform::String), van en naar een back-uparchief.

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;
};

De klasse MarbleMazeMain bevat een PersistentState-object. De constructor van MarbleMazeMain initialiseert dit object en biedt de lokale applicatiegegevensopslag als onderliggende gegevensarchief.

m_persistentState = ref new PersistentState();

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

Marble Maze slaat zijn status op wanneer het marmer een controlepunt of het doel passeert (in de methode MarbleMazeMain::Update) en wanneer het venster de focus verliest (in de methode MarbleMazeMain::OnFocusChange). Als uw game een grote hoeveelheid statusgegevens bevat, raden we u aan om af en toe de status op te slaan in permanente opslag, omdat u slechts een paar seconden hebt om te reageren op de melding voor onderbreken. Daarom hoeft uw app alleen de statusgegevens op te slaan die zijn gewijzigd wanneer uw app een melding voor onderbreken ontvangt.

Als u wilt reageren op meldingen voor onderbreken en hervatten, definieert de klasse MarbleMazeMain de SaveState- en LoadState-methoden die worden aangeroepen voor onderbreken en hervatten. De methode MarbleMazeMain::OnSuspending verwerkt het suspenderevenement en de methode MarbleMazeMain::OnResuming verwerkt het hervattevenement.

De MarbleMazeMain::OnSuspending methode slaat de gamestatus op en onderbreekt audio.

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

De methode MarbleMazeMain::SaveState slaat gamestatuswaarden op, zoals de huidige positie en snelheid van het marmer, het meest recente controlepunt en de tabel met hoge score.

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);
    }
}

Wanneer de game wordt hervat, hoeft het alleen de audio te hervatten. De status van permanente opslag hoeft niet te worden geladen omdat de status al in het geheugen is geladen.

Hoe het spel audio onderbreekt en hervat, wordt uitgelegd in het document Audio toevoegen aan het Marble Maze-voorbeeld.

Ter ondersteuning van opnieuw opstarten roept de MarbleMazeMain constructor, die wordt aangeroepen tijdens het opstarten, de methode MarbleMazeMain::LoadState aan. De methode MarbleMazeMain::LoadState leest en past de status toe op de gameobjecten. Met deze methode wordt ook ingesteld dat de huidige gamestatus op pauze wordt gezet als het spel gepauzeerd of actief was op het moment van onderbreking. We onderbreken het spel zodat de gebruiker niet wordt verrast door onverwachte activiteit. Het wordt ook verplaatst naar het hoofdmenu als het spel niet in een gameplay-status was toen het werd onderbroken.

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);
    }
}

Belangrijk

Marble Maze maakt geen onderscheid tussen koud starten, dat wil zeggen, voor de eerste keer starten zonder een eerdere onderbreking, en hervatten vanuit een geschorste toestand. Dit wordt aanbevolen voor alle UWP-apps.

Voor meer informatie over app-gegevens, zie Instellingen opslaan en ophalen en andere app-gegevens.

Volgende stappen

Lees Visuele inhoud toevoegen aan het Marble Maze-voorbeeld voor informatie over enkele van de belangrijkste procedures waarmee u rekening moet houden wanneer u met visuele resources werkt.