A banner image showing two windows

//Window App

Tätigkeit

Zusammenfassung

Inspiriert von Jason Gregorys Game Engine Architecture arbeite ich seit einiger Zeit an einer Anwendung, in der ich mein theoretisches Wissen testen und meine neuen Ideen ausprobieren kann. In dieser Sandbox entwickle ich eine Anwendung, die viele Komponenten einer Game Engine beinhalten soll. So möchte ich nach und nach immer mehr über die Entwicklung von Spielen lernen und mir neue Fähigkeiten aneignen.

Ich habe mich durch diese Anwendung mit der Windows API vertraut gemacht und einiges über die Architektur von Windows Applikationen sowie Game Engines gelernt. Auf einige der Komponenten möchte ich hier eingehen.

Grundlegender Aufbau

Mein Ziel ist es, dass die Anwendung ein Fenster öffnet, auf dem Text sowie 2D/3D Grafiken und UI angezeigt werden kann. In einem solchen Fall bietet sich der WinMain Einstiegspunkt an. Da ich jedoch Debug-Informationen nicht nur in die Visual Studio Konsole ausgeben möchte, habe ich mich für eine Konsolenanwendung entschieden. Diese öffnet dann im Anschluss kontrolliert ein Fenster und initialisiert die Message Pump.

A gif showing opening windows

Debugging && Logging

Um meine Anwendung korrekt entwickeln zu können muss natürlich ein gutes Logging System her. Dafür habe ich eine Struktur implementiert, die Strings in die Konsole ausgeben kann. Auf diesem Logging System baut dann das Debugging System auf, das standardmäßig zusätzlich zur Log-Nachricht die Uhrzeit und einen optionalen Topic-Tag ausgibt. Für Fehler und Assertions gibt es ebenfalls ein eigenes System. Damit können Fehlermedungen und Warnungen ausgegeben werden, die zusätzlich auch die File-Location sowie die Zeile des Fehlers ausgeben. Assertions beenden hier auch klassischerweise das Programm, wobei die Konsole praktischerweise offen bleibt, sodass wertvolle Informationen über die Assertion sichtbar bleiben.

A gif showing logged messages

Strings

Da Strings bekanntlich performance-kritisch sind, habe ich eine eigene String Klasse geschrieben, die Strings effizienter gestalten soll. Nach Jason Gregorys Vorschlag aus Game Engine Architecture beinhaltet die Klasse eine globale String-Tabelle. Innerhalb der Tabelle werden Strings als Hash und als char* abgebildet. Somit sind String-Zuweisungen, -Vergleiche und das Erstellen neuer Strings mit bereits hinterlegtem Text deutlich performanter. Für das Hashing wird ein 64bit Fast CRC-Hash Algorithmus verwendet. Später könnte die String-Klasse beispielsweise die verwendeten Strings zur Compiletime Serialisieren und könnte dann im besten Fall ausschließlich mittels der Hash-Werte betrieben werden.

Der Source-Code der String-Klasse steht hier zur Einsicht zur Verfügung.

Unit Tests

Bereits zu beginn der Entwicklung habe ich großen Wert auf Unit-Tests gelegt. Dass Unit-Tests eine wertvolle Angewohnheit sind, habe ich sowohl in meinem Studium (Game Engine Programming, Systems Engineering and Management, ...) gelernt, als auch in diesem Projekt. Ähnlich wie Assertions falsche Annahmen bzw. fehlerhafte Daten konsequent aufdecken, haben mir die Unit-Tests effektiv gezeigt, wo sich Fehler eingeschlichen haben. Die Implementierung von Tests war zwar sehr zeitintensiv, hat sich jedoch (fast) immer ausgezahlt. Die Tests werden über das Kommandozeilenargument -test aktiviert und ausgeführt. Zukünftige Anpassungen meiner Tests sollen die Routine um Function-Tests und randomisierte Tests erweitern.

An image showing unittests

Memory Allocation

Für die Anwendung habe ich zwei eigene Memory Allocator implementiert. Einen Stack-Allocator und einen Pool Allocator. Der Stack-Allocator ist mit einem einfachen Pointer auf die oberste Speicheradresse des Stacks umgesetzt. Es können außerdem beliebig Marker gesetzt werden, um den Speicher wieder freizugeben. Der Pool Allocator erzeugt eine Anzahl an Speicher-Blöcken, deren Größe und Anzahl bei der Initialisierung des Allocators angegeben werden. In Zukunft sollen beide Allocator noch mit einer automatischen Alignment-Funktion ausgestattet werden, sodass das Lesen und Schreiben möglichst effizient ist. Beide Allocator sind in die Unit-Tests eingebunden, um Fehlverhalten frühzeitig zu erkennen.

Der Source-Code des Stack-Allocators steht hier zur Einsicht zur Verfügung.
Der Source-Code des Pool-Allocators steht hier zur Einsicht zur Verfügung.

...

Für die Zukunft sind noch viele weitere Strukturen, Klassen und Subsysteme geplant, die in die Anwendung einfließen sollen. Diese werde ich hier zu gegebenem Anlass nachtragen. Themen, die mich interessieren und die dann auch auf dieser Seite veröffentlicht werden, sind Multithreading (insbesondere ein Job System), D3D11/12 und oder Vulkan Rendering, ein Entity-Component-System und viele weitere.

A button to return to the top end of the page

Diese Webseite verwendet keine Cookies und speichert keine Daten.
Viel Spaß beim surfen!

Alles klar!