User Tools

Site Tools


z:code:gamemanager

This is an old revision of the document!


SectorMania Code - GameManager und Startup

Der GameManager ist nicht unbedingt das Herz des Spiels, aber de facto der Rahmen. Er ist zuständig für die Initialisierung des Spiels und entsprechend auch den Shutdown und bringt die Main Loop ans Laufen.

Startup

Der Einstiegspunkt main (bzw. später WinMain für Windows) befindet sich naheliegenderweise in main.cpp. Die Funktion hat nicht viel zu tun, im Wesentlichen erzeugt sie eine Instanz des GameManagers und bringt ihn ans Laufen. Darüber hinaus werden hier unbehandelte Exceptions abgefangen, die gemäß der Plattform dem User mitgeteilt werden und dann einen Shutdown des GameManagers auslösen. Eine Besonderheit von main ist die Schleife, in der der GameManager erzeugt und gestartet wird. Die Schleife hat die Funktion, dass das Spiel im Prinzip beliebig oft reinitialisiert, also beinahe neu gestartet werden kann. Das ist insofern interessant als dass Änderungen an den Grafiksettings in den meisten Fällen einen Neustart erfordern. Solange der User im Hauptmenu ist, kann sich das Spiel so also quasi selbst neustarten, um die neuen Einstellungen zu übernehmen (in einem laufenden Szenario wäre das aber problematisch und werden wir folglich nicht unterstützen). Das funktioniert dann so, dass die Hauptfunktion von GameManager, run(), einen Rückgabewert hat, der signalisiert, ob eine Reinitialisierung gewünscht ist oder nicht. Falls nicht, wird die Schleife verlassen und das Spiel beendet sich.

Übersicht GameManager

Ein Blick in SMGameManager.h offenbart neben ein paar wenigen #includes zunächst eine ganze Reihe von forward declarations für alle Objekte, die der GameManager nutzt. Die meisten dieser Objekte sind prinzipiell Singletons (obwohl formal derzeit nicht als solche implementiert, was ungünstig ist, dazu später mehr), von ihnen existiert also im Spiel nur jeweils eine Instanz, die der GameManager verwaltet (im Moment verwaltet er aber zu viel, auch dazu später mehr). Dann kommt die Deklaration der eigenlichen Klasse GameManager; wie man sieht, ist sie als Ogre-Singleton implementiert, was einen globalen Zugriffspunkt auf die GameManager-Instanz für alle anderen Klassen ermöglicht (via GameManager::getSingleton() ). Außerdem leitet sie von einigen Listener-Interfaces ab, die benutzt werden, um auf bestimmte Ereignisse reagieren zu können. Die geerbten Interface-Funktionen werden weiter unten im public-Abschnitt der Klasse definiert. Zunächst kommen aber die eigenen Funktionen: Neben Konstruktor und Destruktor gibt es offensichtlich das Trio initialise / run / shutdown. initialise und run werden von main aufgerufen, shutdown wird von anderen Stellen aufgerufen, wenn sich das Spiel beenden (bzw. neustarten) soll. Darüber hinaus finden sich die Utility-Funktionen getScreenWidth/Height sowie renderOneFrame, das effektiv dafür sorgt, dass Ogre einen neuen Frame rendert (wer hätte das gedacht). Schließlich gibt es eine Reihe Accessor-Funktionen, die Zugriff auf einzelne Objekte ermöglichen und größtenteils leider unglücklich sind (mehr dazu unten). Im private-Teil dann folgen einige Funktionen, die effektiv die Aufgaben des initialise/run-Paares unterteilen in Teilaufgaben. Ihre Namen dürften die Zuständigkeiten preisgeben. Schließlich folgen die Member-Variablen.

Initialisierungsphase

Der Konstruktor von GameManager setzt zunächst die ganzen Pointer auf die verwalteten Objekte auf 0, das dient dazu, dass wir im Destruktor die Pointer alle einfach löschen (delete) können, egal ob sie gerade angelegt sind oder nicht (delete auf einen Null-Pointer ist erlaubt und tut nichts). Anschließend wird unser virtuelles Dateisystem PhysFS vorbereitet und Ogre darauf vorbereitet, dass wir ein eigenes Log-System verwenden werden (deswegen muss der Ogre-LogManager hier manuell vorab erzeugt werden). Im eigentlichen Initialisierungsvorgang in initialise wird nun zunächst das eigene HTML-Log angelegt und die Konfigurationsdatei des Spiels eingelesen, dies erledigt die Klasse Configuration, deren Instanz GameManager verwaltet. Dann wird Ogre selbst initialisiert, Ogre::Root wird angelegt und das erste verfügbare Rendersystem gewählt. Dann wird PhysFS Ogre als Ressourcenquelle bekannt gemacht und ein Arbeitsverzeichnis “temp” in PhysFS angelegt (hier werden später mal Mapdateien etc. hin entpackt während des Spiels). Weiter geht's dann mit der Erzeugung des Spielfensters und der Anlegung unseres InputManagers (offensichtlich für Spielereingaben, via OIS). initScene erzeugt die Basics von Ogre, die wir fürs Rendern brauchen, also SceneManager, Camera, Viewport, und initGUI() schließlich lädt die GUI-Ressourcen und initialisiert CEGUI. Dann folgt das Anlegen des Localisation-Objekts, dies ist die Klasse, die String-Referenzen wie “MainMenuSkirmish” in die jeweils verwendete Sprache auflöst (in diesem Fall aber wohl fast immer in “Skirmish”) und damit eine Übersetzung des Spiels möglich macht. Der KeyMapper abstrahiert Tastatureingaben, so dass der Spieler verschiedene Aktionen beliebig mit Tasten belegen kann. Anschließend werden dann die Spielressourcen geladen. Der Aufruf zu initShadows() ist sehr temporär, die ganze Schattenlösung ist momentan noch mehr ein Platzhalter, bis das irgendwann wirklich finalisiert ist, am besten im Moment keine Beachtung schenken ;) Zum Schluss werden noch SoundManager und CellPartitioner (der eigentlich nicht hierhin gehört) angelegt und ein paar abschließende Initialisierungen getätigt.

z/code/gamemanager.1211718696.txt.gz · Last modified: 2015/08/23 14:03 (external edit)