Hinzufügen einer Benutzeroberfläche

Hinweis

Dieses Thema ist Teil der Erstellen eines einfachen UWP-Spiels (Universelle Windows-Plattform) mit DirectX-Tutorial-Reihe. Das Thema unter diesem Link legt den Kontext für die Reihe fest.

Jetzt, wo unser Spiel seine 3D-Grafik hat, ist es an der Zeit, sich auf das Hinzufügen einiger 2D-Elemente zu konzentrieren, damit das Spiel dem Spieler Feedback über den Spielzustand geben kann. Dies kann durch das Hinzufügen von einfachen Menüoptionen und Heads-up-Display-Komponenten zur 3-D-Grafik-Pipeline-Ausgabe erreicht werden.

Hinweis

Wenn Sie den neuesten Spielcode für dieses Beispiel nicht heruntergeladen haben, gehen Sie zu Direct3D-Beispielspiel. Dieses Beispiel ist Teil einer großen Sammlung von UWP-Featurebeispielen. Anweisungen zum Herunterladen des Beispiels finden Sie unter Beispielanwendungen für die Windows-Entwicklung.

Ziel

Fügen Sie mithilfe von Direct2D eine Reihe von Benutzeroberflächengrafiken und Verhaltensweisen zu unserem UWP-DirectX-Spiel hinzu:

Das Overlay der Benutzeroberfläche

Obwohl es viele Möglichkeiten gibt, Text und Elemente der Benutzeroberfläche in einem DirectX-Spiel anzuzeigen, werden wir uns auf die Verwendung von Direct2D konzentrieren. Wir werden auch DirectWrite für die Textelemente verwenden.

Direct2D ist ein Satz von 2D-Zeichen-APIs, die zum Zeichnen von pixelbasierten Primitiven und Effekten verwendet werden. Wenn man mit Direct2D anfängt, ist es am besten, die Dinge einfach zu halten. Komplexe Layouts und das Verhalten der Benutzeroberfläche erfordern Zeit und Planung. Wenn Ihr Spiel eine komplexe Benutzeroberfläche erfordert, wie sie in Simulations- und Strategiespielen zu finden ist, sollten Sie stattdessen XAML verwenden.

Hinweis

Informationen zur Entwicklung einer Benutzeroberfläche mit XAML in einem UWP-DirectX-Spiel finden Sie unter Erweitern des Beispielspiels.

Direct2D ist nicht speziell für Benutzeroberflächen oder Layouts wie HTML und XAML konzipiert. Es bietet keine Komponenten der Benutzeroberfläche wie Listen, Kästchen oder Schaltflächen. Es bietet auch keine Layout-Komponenten wie Divs, Tabellen oder Raster.

Für dieses Beispielspiel haben wir zwei Hauptkomponenten der Benutzeroberfläche.

  1. Ein Head-up-Display für den Spielstand und die Steuerung im Spiel.
  2. Ein Overlay zur Anzeige des Spielstatus und von Optionen wie Pauseninfo und Levelstartoptionen.

Verwendung von Direct2D für ein Heads-up-Display

Das folgende Bild zeigt das Heads-up-Display im Spiel für das Beispiel. Es ist einfach und übersichtlich, so dass sich der Spieler auf das Navigieren in der 3D-Welt und das Schießen auf Ziele konzentrieren kann. Eine gute Benutzeroberfläche oder ein Heads-up-Display darf es dem Spieler nicht erschweren, die Ereignisse im Spiel zu verarbeiten und darauf zu reagieren.

ein Screenshot des Spiel-Overlays

Das Overlay besteht aus den folgenden grundlegenden Primitiven.

  • DirectWrite Text in der oberen rechten Ecke, der den Spieler über Folgendes informiert
    • Erfolgreiche Treffer
    • Anzahl der Schüsse, die der Spieler abgegeben hat
    • Verbleibende Zeit im Level
    • Nummer des aktuellen Levels
  • Zwei sich schneidende Liniensegmente, die ein Fadenkreuz bilden
  • Zwei Rechtecke an den unteren Ecken für den move-look controller-Grenzen.

Der Anzeigezustand des Overlays im Spiel wird in der Methode GameHud::Render der Klasse GameHud gezeichnet. Bei dieser Methode wird das Direct2D-Overlay, das unsere Benutzeroberfläche darstellt, aktualisiert, um die Änderungen in der Anzahl der Treffer, der verbleibenden Zeit und der Levelnummer wiederzugeben.

Wenn das Spiel initialisiert wurde, fügen wir TotalHits(), TotalShots() und TimeRemaining() zu einem swprintf_s Puffer hinzu und geben das Druckformat an. Wir können ihn dann mit der Methode DrawText zeichnen. Das Gleiche gilt für die Anzeige der aktuellen Stufe, wobei leere Zahlen wie ➀ für nicht abgeschlossene Stufen und gefüllte Zahlen wie ➊ für abgeschlossene Stufen angezeigt werden.

Der folgende Codeschnipsel führt durch den Prozess der Methode GameHud::Render für

void GameHud::Render(_In_ std::shared_ptr<Simple3DGame> const& game)
{
    auto d2dContext = m_deviceResources->GetD2DDeviceContext();
    auto windowBounds = m_deviceResources->GetLogicalSize();

    if (m_showTitle)
    {
        d2dContext->DrawBitmap(
            m_logoBitmap.get(),
            D2D1::RectF(
                GameUIConstants::Margin,
                GameUIConstants::Margin,
                m_logoSize.width + GameUIConstants::Margin,
                m_logoSize.height + GameUIConstants::Margin
                )
            );
        d2dContext->DrawTextLayout(
            Point2F(m_logoSize.width + 2.0f * GameUIConstants::Margin, GameUIConstants::Margin),
            m_titleHeaderLayout.get(),
            m_textBrush.get()
            );
        d2dContext->DrawTextLayout(
            Point2F(GameUIConstants::Margin, m_titleBodyVerticalOffset),
            m_titleBodyLayout.get(),
            m_textBrush.get()
            );
    }

    // Draw text for number of hits, total shots, and time remaining
    if (game != nullptr)
    {
        // This section is only used after the game state has been initialized.
        static const int bufferLength = 256;
        static wchar_t wsbuffer[bufferLength];
        int length = swprintf_s(
            wsbuffer,
            bufferLength,
            L"Hits:\t%10d\nShots:\t%10d\nTime:\t%8.1f",
            game->TotalHits(),
            game->TotalShots(),
            game->TimeRemaining()
            );

        // Draw the upper right portion of the HUD displaying total hits, shots, and time remaining
        d2dContext->DrawText(
            wsbuffer,
            length,
            m_textFormatBody.get(),
            D2D1::RectF(
                windowBounds.Width - GameUIConstants::HudRightOffset,
                GameUIConstants::HudTopOffset,
                windowBounds.Width,
                GameUIConstants::HudTopOffset + (GameUIConstants::HudBodyPointSize + GameUIConstants::Margin) * 3
                ),
            m_textBrush.get()
            );

        // Using the unicode characters starting at 0x2780 ( ➀ ) for the consecutive levels of the game.
        // For completed levels start with 0x278A ( ➊ ) (This is 0x2780 + 10).
        uint32_t levelCharacter[6];
        for (uint32_t i = 0; i < 6; i++)
        {
            levelCharacter[i] = 0x2780 + i + ((static_cast<uint32_t>(game->LevelCompleted()) == i) ? 10 : 0);
        }
        length = swprintf_s(
            wsbuffer,
            bufferLength,
            L"%lc %lc %lc %lc %lc %lc",
            levelCharacter[0],
            levelCharacter[1],
            levelCharacter[2],
            levelCharacter[3],
            levelCharacter[4],
            levelCharacter[5]
            );
        // Create a new rectangle and draw the current level info text inside
        d2dContext->DrawText(
            wsbuffer,
            length,
            m_textFormatBodySymbol.get(),
            D2D1::RectF(
                windowBounds.Width - GameUIConstants::HudRightOffset,
                GameUIConstants::HudTopOffset + (GameUIConstants::HudBodyPointSize + GameUIConstants::Margin) * 3 + GameUIConstants::Margin,
                windowBounds.Width,
                GameUIConstants::HudTopOffset + (GameUIConstants::HudBodyPointSize + GameUIConstants::Margin) * 4
                ),
            m_textBrush.get()
            );

        if (game->IsActivePlay())
        {
            // Draw the move and fire rectangles
            ...
            // Draw the crosshairs
            ...
        }
    }
}

Wenn man die Methode weiter herunterbricht, zeichnet dieser Teil der Methode GameHud::Render unsere Bewegungs- und Feuerrechtecke mit ID2D1RenderTarget::DrawRectangleund Fadenkreuze mit zwei Aufrufen von ID2D1RenderTarget::DrawLine.

// Check if game is playing
if (game->IsActivePlay())
{
    // Draw a rectangle for the touch input for the move control.
    d2dContext->DrawRectangle(
        D2D1::RectF(
            0.0f,
            windowBounds.Height - GameUIConstants::TouchRectangleSize,
            GameUIConstants::TouchRectangleSize,
            windowBounds.Height
            ),
        m_textBrush.get()
        );
    // Draw a rectangle for the touch input for the fire control.
    d2dContext->DrawRectangle(
        D2D1::RectF(
            windowBounds.Width - GameUIConstants::TouchRectangleSize,
            windowBounds.Height - GameUIConstants::TouchRectangleSize,
            windowBounds.Width,
            windowBounds.Height
            ),
        m_textBrush.get()
        );

    // Draw the cross hairs
    d2dContext->DrawLine(
        D2D1::Point2F(windowBounds.Width / 2.0f - GameUIConstants::CrossHairHalfSize,
            windowBounds.Height / 2.0f),
        D2D1::Point2F(windowBounds.Width / 2.0f + GameUIConstants::CrossHairHalfSize,
            windowBounds.Height / 2.0f),
        m_textBrush.get(),
        3.0f
        );
    d2dContext->DrawLine(
        D2D1::Point2F(windowBounds.Width / 2.0f, windowBounds.Height / 2.0f -
            GameUIConstants::CrossHairHalfSize),
        D2D1::Point2F(windowBounds.Width / 2.0f, windowBounds.Height / 2.0f +
            GameUIConstants::CrossHairHalfSize),
        m_textBrush.get(),
        3.0f
        );
}

In der Methode GameHud::Render speichern wir die logische Größe des Spielfensters in der Variable windowBounds . Dazu wird die Methode GetLogicalSize der Klasse DeviceResources verwendet.

auto windowBounds = m_deviceResources->GetLogicalSize();

Die Ermittlung der Größe des Spielfensters ist für die UI-Programmierung unerlässlich. Die Größe des Fensters wird in DIPs (device independent pixels) angegeben, wobei ein DIP als 1/96 eines Zolls definiert ist. Direct2D skaliert die Zeichnungseinheiten auf tatsächliche Pixel, wenn die Zeichnung erfolgt, indem es die Windows-Einstellung für Punkte pro Zoll (DPI) verwendet. Ähnlich verhält es sich, wenn Sie Text mit DirectWrite zeichnen. Dabei geben Sie DIPs statt Punkte für die Größe der Schrift an. DIPs werden als Gleitkommazahlen ausgedrückt. 

Anzeige der Spielstatusinformationen

Neben dem Heads-up-Display verfügt das Beispielspiel über ein Overlay, das sechs Spielzustände darstellt. Alle Zustände sind mit einem großen schwarzen Rechteck versehen, in dem der Spieler einen Text lesen kann. Die Rechtecke und das Fadenkreuz des Move-Look-Controllers werden nicht gezeichnet, da sie in diesen Zuständen nicht aktiv sind.

Das Overlay wird mit der Klasse GameInfoOverlay erstellt, die es uns ermöglicht, den angezeigten Text an den Zustand des Spiels anzupassen.

status und Wirkung des Overlays

Das Overlay ist in zwei Abschnitte unterteilt: Status und Aktion. Der Bereich Status ist weiter unterteilt in die Rechtecke Titel und Körper. Der Bereich Aktion hat nur ein Rechteck. Jedes Rechteck hat einen anderen Zweck.

  • titleRectangle Enthält den Titeltext.
  • bodyRectangle Enthält den Textkörper.
  • actionRectangle Enthält den Text, der den Spieler auffordert, eine bestimmte Aktion durchzuführen.

Das Spiel hat sechs Zustände, die eingestellt werden können. Der Status des Spiels wird über den Status Teil des Overlays übermittelt. Die Rechtecke von Status werden mit einer Reihe von Methoden aktualisiert, die den folgenden Zuständen entsprechen.

  • Laden
  • Start-/Highscore-Statistiken
  • Level Start
  • Spiel pausiert
  • Spielende
  • Gewonnenes Spiel

Der Action Teil des Overlays wird mit der Methode GameInfoOverlay::SetAction aktualisiert, so dass der Aktionstext auf einen der folgenden Werte gesetzt werden kann.

  • „Tippen Sie auf , um erneut zu spielen...“
  • „Level wird geladen, bitte warten ...“
  • „Tippen Sie auf , um fortzufahren ...“
  • Keine

Hinweis

Diese beiden Methoden werden im Abschnitt Darstellung des Spielzustands näher erläutert.

Je nachdem, was im Spiel passiert, werden die Textfelder der Abschnitte Status und Aktion angepasst. Schauen wir uns an, wie wir das Overlay für diese sechs Zustände initialisieren und zeichnen.

Initialisieren und Zeichnen des Overlays

Die sechs Zustände von Status haben einige Gemeinsamkeiten, so dass die Mittel und Methoden, die sie benötigen, sehr ähnlich sind. – Sie verwenden alle ein schwarzes Rechteck in der Mitte des Bildschirms als Hintergrund. – Der angezeigte Text ist entweder Titel oder Textkörper . – Der Text verwendet die Schriftart Segoe UI und wird über das hintere Rechteck gezeichnet.

Das Beispielspiel verfügt über vier Methoden, die bei der Erstellung des Overlays zum Tragen kommen.

GameInfoOverlay::GameInfoOverlay

Der Konstruktor GameInfoOverlay::GameInfoOverlay initialisiert das Overlay und verwaltet die Bitmap-Oberfläche, die wir zur Anzeige von Informationen für den Spieler verwenden werden. Der Konstruktor erhält eine Fabrik von dem ID2D1Device-Objekt, das ihm übergeben wurde, und verwendet diese, um einen ID2D1DeviceContext zu erstellen, auf den das Overlay-Objekt selbst zeichnen kann. IDWriteFactory::CreateTextFormat

GameInfoOverlay::CreateDeviceDependentResources

GameInfoOverlay::CreateDeviceDependentResources ist unsere Methode zum Erstellen von Pinseln, die zum Zeichnen unseres Textes verwendet werden sollen. Zu diesem Zweck erhalten wir ein ID2D1DeviceContext2-Objekt, das die Erstellung und das Zeichnen von Geometrien sowie Funktionen wie das Rendern von Tinten- und Gradientennetzen ermöglicht. Dann erstellen wir eine Reihe von farbigen Pinseln mit ID2D1SolidColorBrush, um die folgenden UI-Elemente zu zeichnen.

  • Schwarzer Pinsel für rechteckige Hintergründe
  • Weißer Pinsel für Statustext
  • Oranger Pinsel für Aktionstext

DeviceResources::SetDpi

Die Methode DeviceResources::SetDpi legt die Punkte pro Zoll des Fensters fest. Diese Methode wird aufgerufen, wenn die DPI geändert wird und neu angepasst werden muss, was geschieht, wenn das Spielfenster in der Größe verändert wird. Nach der Aktualisierung des DPI ruft diese Methode auchDeviceResources::CreateWindowSizeDependentResources auf, um sicherzustellen, dass die erforderlichen Ressourcen bei jeder Größenänderung des Fensters neu erstellt werden.

GameInfoOverlay::CreateWindowsSizeDependentResources

Die Methode GameInfoOverlay::CreateWindowsSizeDependentResources ist der Ort, an dem alle unsere Zeichnungen stattfinden. Im Folgenden werden die einzelnen Schritte der Methode beschrieben.

  • Es werden drei Rechtecke erstellt, um den UI-Text für die Texte Titel, Textkörper und Aktion abzugrenzen.

    m_titleRectangle = D2D1::RectF(
        GameInfoOverlayConstant::SideMargin,
        GameInfoOverlayConstant::TopMargin,
        overlaySize.width - GameInfoOverlayConstant::SideMargin,
        GameInfoOverlayConstant::TopMargin + GameInfoOverlayConstant::TitleHeight
        );
    m_actionRectangle = D2D1::RectF(
        GameInfoOverlayConstant::SideMargin,
        overlaySize.height - (GameInfoOverlayConstant::ActionHeight + GameInfoOverlayConstant::BottomMargin),
        overlaySize.width - GameInfoOverlayConstant::SideMargin,
        overlaySize.height - GameInfoOverlayConstant::BottomMargin
        );
    m_bodyRectangle = D2D1::RectF(
        GameInfoOverlayConstant::SideMargin,
        m_titleRectangle.bottom + GameInfoOverlayConstant::Separator,
        overlaySize.width - GameInfoOverlayConstant::SideMargin,
        m_actionRectangle.top - GameInfoOverlayConstant::Separator
        );
    
  • Mit CreateBitmap wird eine Bitmap mit dem Namen m_levelBitmap unter Berücksichtigung des aktuellen DPI-Wertes erstellt.

  • m_levelBitmap wird als 2D-Rendering-Ziel mit ID2D1DeviceContext::SetTarget festgelegt.

  • Die Bitmap wird mit ID2D1RenderTarget::Clear geleert, wobei jedes Pixel schwarz wird.

  • ID2D1RenderTarget::BeginDraw wird aufgerufen, um das Zeichnen zu starten.

  • DrawText wird aufgerufen, um den in m_titleString, m_bodyString und m_actionString gespeicherten Text unter Verwendung des entsprechenden ID2D1SolidColorBrush in das entsprechende Rechteck zu zeichnen.

  • ID2D1RenderTarget::EndDraw wird aufgerufen, um alle Zeichenoperationen auf m_levelBitmap zu beenden.

  • Ein weiteres Bitmap wird mit CreateBitmap unter dem Namen m_tooSmallBitmap erstellt, um als Fallback zu dienen und nur angezeigt zu werden, wenn die Anzeigekonfiguration für das Spiel zu klein ist.

  • Wiederholen Sie den Vorgang des Zeichnens auf m_levelBitmap für m_tooSmallBitmap, wobei Sie dieses Mal nur die Zeichenfolge Paused in den Körper zeichnen.

Jetzt brauchen wir nur noch sechs Methoden, um den Text unserer sechs Überlagerungszustände zu füllen!

Darstellung des Spielzustands

Jeder der sechs Overlay-Zustände im Spiel hat eine entsprechende Methode im Objekt GameInfoOverlay. Diese Methoden zeichnen eine Variation des Overlays, um dem Spieler explizite Informationen über das Spiel selbst zu vermitteln. Diese Mitteilung wird mit einer Zeichenfolge Titel und Körper dargestellt. Da das Beispiel die Ressourcen und das Layout für diese Informationen bereits bei der Initialisierung und mit der Methode GameInfoOverlay::CreateDeviceDependentResources konfiguriert hat, müssen nur die für den Overlay-Zustand spezifischen Zeichenfolgen bereitgestellt werden.

Der Status Teil des Overlays wird mit einem Aufruf einer der folgenden Methoden gesetzt.

Zustand des Spiels Methode zum Setzen des Status Statusfelder
Laden GameInfoOverlay::SetGameLoading Title
Laden von Ressourcen
Body
Druckt inkrementell „.“, um eine Ladeaktivität anzuzeigen.
Start-/Highscore-Statistiken GameInfoOverlay::SetGameStats Titel
High Score
Body
Levels Completed #
Total Points #
Total Shots #
Level Start GameInfoOverlay::SetLevelStart Titel
Level #
Textkörper
Beschreibung des Levelziels.
Spiel pausiert GameInfoOverlay::SetPause Titel
Spiel pausiert
Körper
Keine
Spielende GameInfoOverlay::SetGameOver Titel
Game Over
Body
Levels Completed #
Total Points #
Total Shots #
Levels Completed #
High Score #
Gewonnenes Spiel GameInfoOverlay::SetGameOver Titel
You WON!
Body
Levels Completed #
Total Points #
Total Shots #
Levels Completed #
High Score #

Mit der Methode GameInfoOverlay::CreateWindowSizeDependentResources wurden im Beispiel drei rechteckige Bereiche deklariert, die bestimmten Regionen des Overlays entsprechen.

Mit diesen Bereichen im Hinterkopf, lassen Sie uns einen Blick auf eine der zustandsspezifischen Methoden, GameInfoOverlay::SetGameStats, werfen und sehen, wie das Overlay gezeichnet wird.

void GameInfoOverlay::SetGameStats(int maxLevel, int hitCount, int shotCount)
{
    int length;

    auto d2dContext = m_deviceResources->GetD2DDeviceContext();

    d2dContext->SetTarget(m_levelBitmap.get());
    d2dContext->BeginDraw();
    d2dContext->SetTransform(D2D1::Matrix3x2F::Identity());
    d2dContext->FillRectangle(&m_titleRectangle, m_backgroundBrush.get());
    d2dContext->FillRectangle(&m_bodyRectangle, m_backgroundBrush.get());
    m_titleString = L"High Score";

    d2dContext->DrawText(
        m_titleString.c_str(),
        m_titleString.size(),
        m_textFormatTitle.get(),
        m_titleRectangle,
        m_textBrush.get()
        );
    length = swprintf_s(
        wsbuffer,
        bufferLength,
        L"Levels Completed %d\nTotal Points %d\nTotal Shots %d",
        maxLevel,
        hitCount,
        shotCount
        );
    m_bodyString = std::wstring(wsbuffer, length);
    d2dContext->DrawText(
        m_bodyString.c_str(),
        m_bodyString.size(),
        m_textFormatBody.get(),
        m_bodyRectangle,
        m_textBrush.get()
        );

    // We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
    // is lost. It will be handled during the next call to Present.
    HRESULT hr = d2dContext->EndDraw();
    if (hr != D2DERR_RECREATE_TARGET)
    {
        // The D2DERR_RECREATE_TARGET indicates there has been a problem with the underlying
        // D3D device. All subsequent rendering will be ignored until the device is recreated.
        // This error will be propagated and the appropriate D3D error will be returned from the
        // swapchain->Present(...) call. At that point, the sample will recreate the device
        // and all associated resources. As a result, the D2DERR_RECREATE_TARGET doesn't
        // need to be handled here.
        winrt::check_hresult(hr);
    }
}

Unter Verwendung des Direct2D-Gerätekontextes, den das Objekt GameInfoOverlay initialisiert hat, füllt diese Methode die Titel- und Körperrechtecke mit Schwarz unter Verwendung des Hintergrundpinsels. Es zeichnet den Text für die Zeichenfolge „High Score“ in das Titelrechteck und eine Zeichenfolge mit den Informationen zum aktualisierten Spielstatus in das Körperrechteck, wobei der weiße Textpinsel verwendet wird.

Das Aktionsrechteck wird durch einen nachfolgenden Aufruf von GameInfoOverlay::SetAction aus einer Methode des GameMain-Objekts aktualisiert, das die Spielstatusinformationen bereitstellt, die von GameInfoOverlay::SetAction benötigt werden, um die richtige Nachricht an den Spieler zu bestimmen, z. B. „Tippen Sie, um fortzufahren“.

Das Overlay für einen bestimmten Zustand wird in der Methode GameMain::SetGameInfoOverlay wie folgt ausgewählt:

void GameMain::SetGameInfoOverlay(GameInfoOverlayState state)
{
    m_gameInfoOverlayState = state;
    switch (state)
    {
    case GameInfoOverlayState::Loading:
        m_uiControl->SetGameLoading(m_loadingCount);
        break;

    case GameInfoOverlayState::GameStats:
        m_uiControl->SetGameStats(
            m_game->HighScore().levelCompleted + 1,
            m_game->HighScore().totalHits,
            m_game->HighScore().totalShots
            );
        break;

    case GameInfoOverlayState::LevelStart:
        m_uiControl->SetLevelStart(
            m_game->LevelCompleted() + 1,
            m_game->CurrentLevel()->Objective(),
            m_game->CurrentLevel()->TimeLimit(),
            m_game->BonusTime()
            );
        break;

    case GameInfoOverlayState::GameOverCompleted:
        m_uiControl->SetGameOver(
            true,
            m_game->LevelCompleted() + 1,
            m_game->TotalHits(),
            m_game->TotalShots(),
            m_game->HighScore().totalHits
            );
        break;

    case GameInfoOverlayState::GameOverExpired:
        m_uiControl->SetGameOver(
            false,
            m_game->LevelCompleted(),
            m_game->TotalHits(),
            m_game->TotalShots(),
            m_game->HighScore().totalHits
            );
        break;

    case GameInfoOverlayState::Pause:
        m_uiControl->SetPause(
            m_game->LevelCompleted() + 1,
            m_game->TotalHits(),
            m_game->TotalShots(),
            m_game->TimeRemaining()
            );
        break;
    }
}

Jetzt hat das Spiel eine Möglichkeit, dem Spieler Textinformationen zu übermitteln, die auf dem Spielstatus basieren, und wir haben eine Möglichkeit, das, was dem Spieler angezeigt wird, während des Spiels zu ändern.

Nächste Schritte

Im nächsten Thema, Hinzufügen von Steuerelementen, sehen wir uns an, wie der Spieler mit dem Beispielspiel interagiert und wie die Eingabe den Spielzustand verändert.