Das Gamesystem-Modul 8
Zeitgeist hatte, obwohl als Framework für Spiele konzipiert, lange Zeit keine eigenen Funktionalitäten die speziell für Spiele ausgelegt sind. Wenn man genauer nachdenkt sind viele Anforderungen an ein PBBG genau die Selben wie für alle anderen Webanwendungen:
- Verwaltung der Nutzer und deren Daten
- Ein Eventhandler zur Ablaufsteuerung
- Konfigurationsmanagement für die Applikation, Sprachen usw.
- Sicherheit und Fehlerbehandlung
Doch welche Eigenschaften und Funktionalitäten brauchen Spiele, die sich nicht aus einem allgemeinen Framework für Webapplikationen ergeben?
Auf der Suche
Am Anfang stand die Idee, dass Zeitgeist ein Framework speziell für Spiele sein sollte. Mit der Zeit wandelte es sich zu einem allgemeinen Framework für Webanwendungen und alle Abläufe für Spiele musste das Spiel selbst liefern. Nach 3 Spiele-Prototypen stellte ich jedoch fest, dass es Elemente gab, die in jedem Spiel vorkommen und somit genauso gut in ein generisches Modul für Spiele ausgelagert werden könnten.
Um zu bestimmen, was ein solches Spielsystem eigentlich können soll, muss man sich darüber im Klaren sein, was ein Spiel aus Sicht einer Applikation eigentlich ist. Ich habe lange hin und her gestrichen und kam schließlich auf folgende Definitionen:
- Jeder Benutzer mit einer Session ist ein potentieller Spieler
- Jede Instanz der Applikation ist ein potentielles Spiel (Sharding)
- Jedes Spiel hat Spieler
- Jeder Spieler hat Metadaten, die seinen Zustand im Spiel beschreiben
- Das Spiel an sich hat ebenfalls Metadaten, welche die Spielwelt definieren
- Spieler agieren mit anderen Spielern und der Spielwelt durch das Spiel
- Jede Interaktion mit dem Spiel wird durch eine Aktion abgebildet
- Aktionen verändern die Metadaten der Spieler und der Spielwelt
- Aktionen können sich unmittelbar oder zukünftig auswirken
Das ergibt folgende Komponenten:
- Aktionsverwaltung: Ein Eventhandler, der alle Aktionen verwaltet, die ein Spieler (oder Spiel) ausführen kann
- Datenhaltung: Ein System, welches alle Daten verwaltet, die einen Spieler oder die Spielwelt betreffen können
Nun, auf den ersten Blick deckt sich die Aktionsverwaltung des Spiels mit der Ablaufsteuerung einer Webapplikation und die Datenhaltung ebenfalls. Brauchen wir wirklich alles nochmal, obwohl das Framework alles schon mitbringt?
Kurze Antwort: ja.
Der Gamehandler
Der Gamehandler besteht im Wesentlichen aus 2 Komponenten: einem Eventhandler, der hereinlaufende Aktionen verwaltet und einem Gamehandler, der die Aktionen auf die Logik mappt.
Eine Aktion des Eventhandlers hat folgende Parameter:
- Aktion: Eine ID für eine Aktion, die auf ein Stück Code gemapped werden kann
- Parameter: Ein Parameter-Objekt, welches dem Aktionscode mitgegeben wird
- Ausführungszeit: Der Zeitpunkt im Spiel, an dem die Aktion relevant wird
- Spieler: Der Spieler, der die Aktion ausgeführt hat
- Shard: Die ID des Shards, auf dem die Aktion ausgeführt wird
- Zeitpunkt: Der Zeitpunkt, an dem die Aktion ausgeführt wurde
Durch die Angabe des Shards wird ermöglicht, dass mehrere Spiele in einer Datenbank abgelegt werden können. Dies ist unabhängig davon, ob die Spiele selbst auf einem oder mehreren Servern laufen. In einem typischen Aufbau-Strategie-PBBG ist es meistens so, dass viele Mitspieler in einem Spiel (bzw. einer Spielwelt) agieren. Bei Spielen mit einer kleinen, abgegrenzten Anzahl von Spielern pro Spiel (Bsp. Tic Tac Toe) laufen viele Spiele gleichzeitig nebeneinander. Solange für jeden Spieler die ID seines eigenen Spiels mitgegeben wird, lassen sich die Daten sauber trennen.
Der Gamehandler mappt die vom Eventhandler aufgenommenen Aktionen auf Klassenobjekte. Jede Aktion steht also für eine externe Klasse, welche für die eigentliche Logik hinter der Aktion sorgt. Was dort dann genau passiert ist nicht mehr Sache des Gamehandlers. Er reicht nur alle relevanten Aktionen für einen gegebenen Zeitpunkt, einen gegebenen Spieler und ein gegebenen Shard weiter.
Alternativ zu dem Gamehandler kann natürlich auch ein permanent laufender Application Server eingesetzt werden, der andauernd die Eventliste abarbeitet.
Datenhaltung
Die Datenhaltung muss für alle Spiele und alle Spieltypen passen. In der Theorie müsste sie also die Daten eines typischen Aufbau-Strategie-PBBG genauso gut verwalten können, wie die einer Tic Tac Toe Plattform.
Das ist natürlich Unsinn. Eine spezialisierte Datenhaltung, die genau auf das Projekt zugeschnitten ist wird immer performanter, aber vor allem auch lesbarer sein, als eine generische. Aber: eine solche spezialisierte Datenhaltung zu entwickeln kostet Zeit. Bei einem Tic Tac Toe mag der Zeitaufwand sehr gering sein, aber man wird schnell an die Grenze stoßen, wo man überlegen muss, ob es sich tatsächlich lohnt sofort auf eine performante Datenhaltung zu optimieren, oder ob nicht erst einmal eine generische genügt.
Aber gibt es Datenstrukturen bzw. Ansätze, mit denen man so unterschiedliche Anforderungen abdecken kann? Antwort: ja, gibt es. Es ist nicht so, als hätte die Spieleindustrie nicht schon lange an dem Problem zu knabbern. Deren Antwort lautet: Entity Systeme.
Die Gamedata-Klasse nimmt sich die Datenhaltung eines Entity Systems zum Vorbild und implementiert diese in PHP. Für Details und Erklärungen der Funktionsweise verweise ich auf den Artikel, der das so wie so viel besser erklärt, als ich hier in Kürze könnte.
Im Einzelfall muss aber jeder selbst entscheiden, ob er diese nutzt, oder ob es sinnvoller ist die Datenhaltung speziell für das Spiel zu entwickeln.
In Aktion
Die letzten beiden Versionen der Spiele-Prototypen wurden mit dem neuen System umgesetzt und ich bin ziemlich zufrieden. Ich werde mich bemühen in den kommenden Wochen ein kleines Spielchen damit (möglichst sauber) zu entwickeln und als Beispiel ins SVN aufzunehmen.
Hallo Dirk,
sehr interessanter Artikel. Ich selbst komme zwar nicht aus der Spieleentwicklung, habe aber jahrelang als Softwareentwickler gearbeitet und beschäftige mich immer gerne mit Architekturen, Patterns & Co.
Den Artikel über ES habe ich auch vor einiger Zeit gefunden. Sehr interessant. Zwei Fragen, die für mich total offen blieben:
1. Wie interagieren Komponenten? Wenn der Zustand der einen vom Zustand einer anderen abhängt, wie wird das realisiert? Immerhin dürfen sie sich ja nicht kennen, sprich ich darf den Zustand gar nicht erst abfragen.
2. Wie gut eignet sich das tatsächlich für Browsergames? Durch die component_data_N – Tabellen ist es ja nicht mehr möglich, effektiv mit Joins zu arbeiten. Dadurch muss ich aber pro Entity zig Queries absetzen (jede component_data – Tabelle) was auf die Performance schlägt. Für z.B. einen Kampf müssten dann auch noch mehrere Entities geladen werden. Das klingt für mich nach einem absoluten NoGo in einem Browsergame.
Mir kam die Artikelreihe daher eher vor, als wäre ES für Clientbasierte-Spiele ausgelegt.
Würde mich freuen, wenn du da einen Hinweis für mich hättest. Dein Framework schaue ich mir auch mal an – bisher kannte ich weder Zeitgeist noch deinen Blog. Aber der ist abonniert!
Hallo Gameplorer,
danke für dein Feedback!
Zu 1) Ganz allgemein gesprochen: Das ist in der Tat nicht definiert und Sache deiner Implementation. Es gab es erst vor Kurzem eine lange und breite Diskussion darüber in der Sweng Gamedev Mailingliste: “Entity Communication & Use of Reflection” von Ashkan Aliabadi, beginnend ab dem 18.12.2009 (verfügbar im Archiv, aber Anmeldung erforderlich). Es gab unheimlich viele interessante Ansichten dazu wie, warum und warum nicht Komponenten und Entitäten miteinander kommunizieren dürfen und sollten.
Zu 2) Ich habe 5 Mal angefangen hier was zu schreiben, aber alles läuft auf einen ähnlich langen Text wie bei dem Hauptartikel hinaus. Also bitte ich um etwas Geduld – ich finde die Frage toll, weil sie in der Tat den Finger auf einen wichtigen Punkt legt, und werde sie in den kommenden Tagen in Artikelform ausführlich beantworten.
Hi Dirk,
dass Komponenten strikt getrennt werden, würde ich (auch ohne praktische ES-Erfahrung) klar befürworten. Allerdings ist mir die Kommunikation gänzlich unklar, da ja die einzelnen Algorithmen in einer Komponente ablaufen müssen (Wiederverwendbarkeit etc.). Wenn sich Komponenten gegenseitig beeinflussen, geht das dann nicht mehr ohne weiteres. Aber danke für deine Links, da schaue ich mal rein.
Falls du es schaffst dazu einen Artikel zu schreiben, wäre das prima. Vor allem der Punkt, dass ich bei einem spezifischen Datenbankdesign einige Berechnungen auf das DBMS auslagern könnte, beim ES nicht mal mehr gescheite Queries (Nachteile bei internen Query-Optimierung, Parallelisierung, Indizes, Performance, etc. pp.) bauen kann, würde mich dabei interessieren.
Der Vorteil den ich jedoch sehe, ist die Wiederverwendbarkeit und Wartbarkeit. Nach meiner Einschätzung kann das aber die enormen Performance-Einbußen nicht aufwiegen.
Aber… ich bin mal auf deinen Artikel gespannt.
Gruß
Dennis
Moment mal – in einer Komponente finden gar keine Algorithmen statt, wir sprechen von reinen Daten. Die Systeme, die auf die Komponenten zugreifen sind diejenigen, die Aktionen durchführen. Die Kommunikation zwischen diesen Systemen findet über einen Eventhandler statt (in meinem Fall zumindest). Ob diese Systeme nun in der Hauptapplikation, in eigenen kleinen Servern oder in der Datenbank laufen ist nicht definiert und kann von Fall zu Fall implementiert werden.
Mehr dazu bald..
Für mich las sich das so, dass Entities keine Klassen sind und auch keine Funktionen anbieten. Die Komponenten implementieren hingegen die Logik. Sonst wären sie ja auch nicht in sich geschlossen und sinnvoll wiederverwendbar, wenn die Logik an ganz anderer Stelle definiert ist.
Allerdings hatte ich bisher auch nur deinen und T=Machines Artikel zum ES und daher noch einige unklare Punkte.
Bis bald!
Kurz erklärt:
- Eine Entity ist ein “Ding innerhalb der Welt”, repräsentiert durch eine ID
- Eine Komponente ist eine “Eigenschaft eines Dings”, repräsentiert durch Daten der Eigenschaft
- Ein System ist die Logik, die auf die Komponenten einwirkt
Beispiel:
- Entity: Raumschiff “Millenium Falcon”
- Beispielhafte Komponente: Aktuelle Position, repräsentiert durch X, Y, Z-Koordinate im Raum
- Beispielhaftes System, welches auf die Komponente einwirkt: Physik
[...] meinem Artikel über das Zeitgeist Gamesystem-Modul habe ich etwas mehr über die Klasse zur Datenhaltung (gamedata.class.php) geschrieben. Diese ist [...]
[...] Leiter bei Deck13) über komponentenbasierte Systeme (auch bekannt als Entity-Systeme). Da meine Artikel zu dem Thema bei euch gut ankamen könnte dieser für euch ebenfalls interessant [...]