© best_vector/Shutterstock.com
Teil 2: Mit DirectX Apps und Spiele für die Xbox One entwickeln

DirectX trifft Xbox


Die Grafikprogrammierschnittstelle von Microsoft kann auf eine wechselvolle Vergangenheit zurückblicken: Vor einiger Zeit gingen Insider sogar davon aus, dass das Produkt aufgegeben werden würde.

Schnittstellen wie Mantle und Vulkan haben auf Seiten Microsofts einen Umdenkprozess ausgelöst: DirectX 12 ist wesentlich hardwarenäher als die Vorgänger. Dies setzt auf Seiten der Entwickler mehr Wissen über den Aufbau der GPU voraus, ist andererseits aber der Weg zum Erreichen von höherer Performance. Für Entwickler von Xbox-Applikationen ist das allerdings nicht von Bedeutung. Microsoft erlaubt ohne Mitgliedschaft im ID@XBox-Programm nämlich nur die Nutzung der Funktionen von DirectX 11. Zudem stehen den Apps nur maximal 45 Prozent der GPU zur Verfügung: Der genaue Anteil liegt in Anbetracht der Auslastung des Gesamtsystems mal höher und mal niedriger.

Nichts wie los

Die Konfiguration der Verbindung einer Xbox zu einer Workstation wurde im vorhergehenden Artikel en detail beschrieben und wird hier als gegeben angenommen. Starten Sie also nun Visual Studio und erstellen Sie ein neues Projekt auf Basis der Vorlage Visual C++ | DirectX 11 App (Universal Windows).

Im Rahmen der Generierung des Projektskeletts muss Visual Studio einige Dateien parsen. Wundern Sie sich nicht, wenn die IDE anfangs einige gültige C++-Statements mit roten Fehlerwellen unterlegt.

Die Debugger-Konfiguration funktioniert unter Vi­sual C++ – das Produkt stand einst außerhalb der Hierarchie von Visual Basic und Co. – etwas anders. Klicken Sie das Projekt im Solution Explorer mit der rechten Maustaste an und wählen Sie im daraufhin erscheinenden Kontextmenü die Option Properties. Wechseln Sie sodann in das Feld Debugging und geben Sie die benötigten Informationen in die Felder Machine Name und Authentication Type ein. Abbildung 1 zeigt die Konfiguration, die im Unternehmen des Autors zum Deployment verwendet wird.

hanna_xboxone_1.tif_fmt1.jpgAbb. 1: So kann der Code auf die Xbox wandern

Microsoft greift Entwicklern aufgrund der hohen Komplexität von DirectX an dieser Stelle insofern unter die Arme, als das Beispielprojekt eine komplette Rendering-Pipeline realisiert: Wer die App ausführt, erfreut sich an einem drehbaren dreidimensionalen Würfel (Abb. 2).

hanna_xboxone_2.tif_fmt1.jpgAbb. 2: Dieser Würfel nimmt uns einiges an Arbeit ab

Von Null an

Fremden bzw. neuartigen Systemen nähert man sich am besten, indem man einen charakteristischen Durchlauf von vorne bis hinten nachverfolgt. Die in app.cpp befindliche main()-Methode erzeugt eine Instanz einer von Windows::ApplicationModel::Core::IFrameworkView abgeleiteten Klasse. Dabei handelt es sich um eine Art Interface, das den DirectX-Teil mit der Universal-Windows-Plattform verdrahtet.

Für uns sind hier nur zwei Stellen interessant: erstens die Load()-Methode, die eine Instanz der eigentlichen Logikklasse erzeugt. m_deviceResources repräsentiert dabei die zugrunde liegende Hardware:

void App::Load(Platform::String^ entryPoint){ if (m_main == nullptr){ m_main = std::unique_ptr<SUS3DApp1Main>(new SUS3DApp1Main(m_deviceResources)); } }

Wichtigkeit Nummer zwei findet sich in der Methode Run(), die den eigentlichen Gameloop realisiert (Listing 1).Die für die Aktualisierung und Darstellung der in der Logik enthaltenen Informationen notwendigen Methoden Update() und Render() liegen im Main-Objekt: Unter DirectX spricht man statt vom in XNA verbreiteten Begriff Draw() von Render. Wichtig ist an dieser Stelle noch die Methode Present(), die GraphicsDevice dazu anweist, die am Bildschirm befindlichen Inhalte zu aktualisieren. GraphicsDevice selbst ist eine Hilfsklasse, die im Unterordner Common liegt: Für’s Erste ist der in ihr befindliche Code nicht relevant.

Listing 1

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(); . . .

Microsoft zeigt schon an dieser Stelle Liebe zur korrekten Entwicklung: Sowohl Render() als auch Update() senden die jeweiligen Events in Richtung zweier Unterklassen, die für die Darstellung des Framerate-Zählers und des Würfels zuständig sind.

Entwickler von Spielen stehen vor der unangenehmen Aufgabe, kontinuierlich ablaufende Echtzeitprozesse in einzelne Zeitschlitze zu diskretisieren. Leider ist die Grafikhardware oft nicht schnell genug, um jeden errechneten Frame auch auf den Bildschirm zu bringen. In diesem Fall führt der Gameloop einen oder mehrere Aufrufe von Update() durch, bevor eine Invokation von Render() folgt:

void SUS3DApp1Main::Update() { m_timer.Tick([&](){ m_sceneRenderer->Update(m_timer); m_fpsTextRenderer->Update(m_timer);

Die hier verwendete Klasse bietet mit der Tick-Funktion einen kleinen Trick an: Je nach Betriebsmodus wird der übergebende Delegat pro Aufruf ein- oder mehrmals hintereinander aufgerufen, um so die notwendigen Aktualisierungen des Bildschirminhalts zu generieren – ist die Engine „hinter der Zeit“, so folgen mehrere Abarbeitungen des Delegaten.

Render liefert True und False zurück: Im vorliegenden Beispiel handelt es sich hier um eine „Fleißübung“ seitens Microsofts, um den Aufruf von Present zu verhinde...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang