- Das 1999 erschienene RollerCoaster Tycoon ist ein fast vollständig in Assembler geschriebenes Simulationsspiel, das Tausende von Gästen in Echtzeit verarbeitet und dabei eine stabile Performance beibehält
- Entwickler Chris Sawyer entschied sich statt für Hochsprachen für Low-Level-Kontrolle und vollendete damit eine der letzten in Assembler geschriebenen Spiele-Generationen mit maximaler CPU-Effizienz
- Durch das Fanprojekt OpenRCT2 wurden die präzisen Optimierungsmuster und Speichertechniken des Originals per Reverse Engineering analysiert
- Das Spiel steigerte Rechengeschwindigkeit und Cache-Effizienz durch Bit-Shift-Operationen und fein abgestufte Datentypen und machte groß angelegte Simulationen durch begrenzte Pfadsuchtiefe und den Verzicht auf Kollisionsberechnungen möglich
- Diese Struktur gilt als Musterbeispiel für Optimierung durch kreative Nutzung technischer Einschränkungen und zeigt bis heute, wie wichtig es ist, unnötige Berechnungen bereits in der Entwurfsphase zu eliminieren
Analyse der Optimierungsstruktur von RollerCoaster Tycoon
- Das 1999 veröffentlichte RollerCoaster Tycoon (RCT) wurde fast vollständig in Assembler (Assembly) geschrieben und gilt als Spiel, das Tausende von Agenten in Echtzeit simulierte und dabei auf der damaligen Hardware stabile Frameraten hielt
- Auf Basis der Behandlung im deutschen Spiele-Podcast Stay Forever wird konkret analysiert, wie Chris Sawyer ein derart extremes Maß an Optimierung erreicht hat
- Der originale Source Code ist zwar nicht öffentlich, doch über das von Fans entwickelte Projekt OpenRCT2 lassen sich Code-Struktur und Optimierungstechniken per Reverse Engineering nachvollziehen
-
Maximale Performance durch Assembler
- RCT wurde nicht in C oder C++, sondern in Assembler geschrieben, was eine deutlich feinere Performance-Kontrolle als bei anderen Spielen der Zeit ermöglichte
- Zum Beispiel wurde Doom (1993) größtenteils in C geschrieben, während RCT fast vollständig in Assembler umgesetzt wurde
- Dieser Ansatz war schon Ende der 1990er-Jahre selten, und RCT gilt als eines der letzten großen Assembler-Spiele
- Da die automatische Optimierung durch Compiler damals noch begrenzt war, machte manuelle Optimierung einen großen Unterschied bei der Performance
-
Code-Analyse mit OpenRCT2
- OpenRCT2 ist ein Open-Source-Projekt von Fans, das das Originalspiel vollständig neu implementiert und dabei die originalen Assets weiterverwendet sowie 100% Kompatibilität beibehält
- Frühe Versionen reproduzierten das Verhalten des Originalcodes nahezu identisch, später kamen verschiedene Verbesserungen hinzu
- Durch dieses Projekt konnten die feingranularen Optimierungsmuster des Originalcodes nachvollzogen werden
-
Feingranulare Datentypen — Speicher sparen
- RCT speichert Geldwerte je nach Kontext in unterschiedlich großen Datentypen
- Beispiel: Der Gesamtwert des Parks nutzt eine 4-Byte-Variable, Ladenpreise eine 1-Byte-Variable
- Diese Granularität diente dazu, Speicher zu sparen und die Cache-Effizienz zu verbessern; auf modernen CPUs ist der Performance-Unterschied nahezu verschwunden, weshalb OpenRCT2 dies auf eine einheitliche 8-Byte-Variable umgestellt hat
-
Optimierung mathematischer Operationen mit Bit Shifts
- Im Code wird die Operation
NewValue = OldValue > verwendet, um Divisionen durch Zweierpotenzen zu ersetzen
- Solche Optimierungen sind nur möglich, wenn Multiplikation oder Division mit Zweierpotenzen erfolgt, weshalb die Formeln im Spiel offenbar selbst auf diese Bedingung zugeschnitten wurden
- Das heißt: Schon im Game-Design wurde eine mathematische Struktur mit Blick auf CPU-Effizienz gewählt
-
Game-Design mit Blick auf Performance
- Da Chris Sawyer bei RCT sowohl Programmierer als auch alleiniger Game-Designer war, konnte er bereits in der Entwurfsphase eine auf Performance ausgerichtete Struktur schaffen
- Ein typisches Beispiel ist das Gäste-System (Pathfinding)
- In den meisten Simulationsspielen wählen Gäste ein Ziel und berechnen einen Weg dorthin, in RCT laufen sie jedoch zufällig umher und entdecken Attraktionen eher zufällig
- Diese Struktur vermeidet groß angelegte Pfadsuchberechnungen und ermöglicht die gleichzeitige Verarbeitung von Tausenden Gästen
- Wenn Pfadsuche doch nötig ist (z. B. wenn ein Mechaniker zu einer defekten Attraktion läuft), wird die Suchtiefe begrenzt, um Frame-Drops zu verhindern
- Normale Gäste suchen nur bis zu 5 Kreuzungen weit, Mechaniker bis zu 8
- Gäste, die eine Karte gekauft haben, erhalten ein Suchlimit von 7
- Diese Grenzen sind keine bloßen technischen Kompromisse, sondern natürlich ins Gameplay integrierte Optimierungsstrukturen
-
Crowd-Verarbeitung und Verzicht auf Kollisionsvermeidung
- RCT verzichtet vollständig auf Kollisionen oder Ausweichberechnungen zwischen Gästen
- Tausende Gäste können sich dieselbe Weg-Kachel teilen
- Stattdessen wird die lokale Bevölkerungsdichte verfolgt, sodass bei hohem Andrang die Zufriedenheit der Gäste sinkt
- Der Spieler muss Überfüllung also weiterhin managen, aber der Rechenaufwand ist deutlich geringer
- Dieser Ansatz gilt als typisches Beispiel dafür, komplexe Physikberechnungen zu entfernen und trotzdem das Spielerlebnis zu erhalten
-
Was sich daraus für moderne Entwicklung ableiten lässt
- Die Optimierung von RCT gilt als Beispiel für den kreativen Umgang mit technischen Einschränkungen
- Auch heute ist ein solcher Ansatz möglich, verlangt aber enge Zusammenarbeit zwischen Programmierern und Designern
- Manchmal bringt es mehr Performance, nicht ein technisches Problem zu lösen, sondern das Problem selbst schon in der Entwurfsphase zu eliminieren
2 Kommentare
Bitte liebt RollerCoaster Tycoon ganz viel.
Hacker-News-Kommentare
Warcraft 1, 2 und StarCraft verwendeten alle Karten mit Größen in Zweierpotenzen
Dadurch konnte man selbst auf langsamen 386/486-CPUs Geschwindigkeit gewinnen, indem man statt Divisionen und Multiplikationen Shift-Operationen nutzte
Karten-Rendering, Sprites, Schriftarten und Nebeleffekte wurden in Tausenden Zeilen Assembler umgesetzt, der Rest war portabler, in C geschriebener Code
Bei Blackthorne wurden die SNES-, Genesis- und DOS-Versionen jeweils manuell in unterschiedlichem Assembler portiert, und für die PC-Version wurden 100.000 Zeilen Rendering-Code per Makro für VGA Mode X erzeugt
Aus diesen Erfahrungen zog Blizzard die Lehre, dass „Assembler zu viel Entwicklungszeit verschlingt“
Comanche: Maximum Overkill war ein vollständig in Assembler geschriebener hubschraubersimulator auf Voxel-Basis, aber weil die Portierung in den Protected Mode zu schwierig war, wechselte man in späteren Versionen zum Polygon-Rendering
EA hat den Quellcode der Command-&-Conquer-Serie veröffentlicht, aber Tiberian Sun und Red Alert 2 fehlten
Es wäre schön gewesen, wenn auch StarCraft aus Gründen der historischen Bewahrung veröffentlicht worden wäre
Von da an war ich vollkommen von Spielen fasziniert
Mich würde auch interessieren, ob du in der Demoszene aktiv warst
Ich selbst war ungefähr zur Veröffentlichung von WC3 kurzzeitig als Berater dort
Wie im Artikel erwähnt, scheinen die Ergebnisse viel beeindruckender zu sein, wenn Designer und Programmierer dieselbe Person sind
Auch in den hierarchischen Strukturen großer Unternehmen kommt am Ende etwas heraus, wenn man nur genug Leute darauf ansetzt, aber wirklich kreative Resultate werden oft im Kopf einer einzelnen Person vollständig geformt
Vielleicht führt auch die Zukunft von KI-Entwicklungstools zu einer Rückkehr in so ein „Zeitalter der Ein-Personen-Entwicklung“
Auch Game-Designer müssen weiterhin numerische Eigenschaften berücksichtigen
Je besser ein Designer ist, desto eher versteht er, dass Dinge wie Recheneffizienz oder Genauigkeit Einfluss auf die Spielbalance haben
Heute ignorieren viele Entwickler das, aber genau das kann eine verborgene Ursache für sinkende Spielqualität sein
Heute liegt man bei etwa 1 Takt für Addition, 3 Takten für Multiplikation und 12 Takten für Division, und mehrere Operationen werden parallel verarbeitet
Zu alten Pentium-Zeiten waren es 46 Takte, bei nur 100 MHz
Heute ist das Speicher-Layout viel wichtiger — ein einziger Cache-Miss kostet 100 bis 1000 Takte
Mit
int[]zu rechnen ist viel schneller als mitMonster[]Es gibt einen Trade-off zwischen Geschwindigkeit, Genauigkeit, Speicherbedarf und Komplexität
Arbeiten wie Toward an API for the Real Numbers schlagen Ansätze vor, solche Probleme schrittweise zu lösen
Es gibt Gleitkommafehler, Intervallarithmetik, symbolische Berechnung und viele andere Methoden, aber am Ende gerät man in Schwierigkeiten, wenn man die Trade-offs nicht versteht
Zum Beispiel berücksichtigte Fumito Ueda bei Shadow of the Colossus die technische Umsetzbarkeit sehr sorgfältig, und auch Doom war eine Verbindung aus Kreativität und Technik
Siehe dazu dieses Interview
Bugs, innere Logik der Geschichte und Immersion sind wichtiger
Natürlich mindern starke Framedrops die Qualität, aber wenn es auf der Zielhardware flüssig läuft, sollte man Verbesserungen auf andere Bereiche konzentrieren
Ich passte ihn so an, dass Konstanten mit Thumb-2-Instruktionen unmittelbar geladen werden konnten, um Speicher-Stalls zu vermeiden
Dadurch ließen sich Zufallszahlen schnell und effizient verwenden, und alle Tests bestanden
Später wurde jedoch auf den Cortex-M0 umgestellt, und der Code wurde verworfen
Ich fand den Teil interessant, in dem technische Beschränkungen in Gameplay-Elemente umgewandelt werden
Das erinnerte mich an das Blood-Moon-System aus The Legend of Zelda
Die Erklärung „Wenn man statt
/8>>3verwendet, kann man sich eine Division sparen“ ist bei modernen Compilern nicht zutreffendWenn der Typ passt, optimiert der Compiler das automatisch zu einer Shift-Operation
Die Erklärung „In Binärdarstellung bedeutet ein Shift nach links Verdopplung“ hat mich erstaunt
Es ist bemerkenswert, dass sich so ein grundlegendes Konzept im Jahr 2026 wieder so fremd anfühlen kann
Die Aussage, „der Compiler wandelt Multiplikationen mit Zweierpotenzen nicht in Shifts um“, ist ein alter Witz
Schon in den 2000ern war das so selbstverständlich, dass Compiler bei solchem Code praktisch gähnen
Hat Spaß gemacht zu lesen. Zu RCT empfehle ich außerdem diese Materialien
Ich frage mich, ob es in großen Studios möglich ist, technische Beschränkungen zu einem prägenden Spielelement zu erheben
So wie Hindernisse im Storytelling eine Geschichte interessanter machen, können Solo-Entwickler technische Grenzen in kreative Elemente umwandeln
Mir fällt zum Beispiel ein Ansatz ein, bei dem Bugs oder Glitches als Minispiel neu interpretiert werden
Beim Pathfinding in RCT musste ich an Marcel Vos’ YouTube-Video denken
Er veröffentlicht viele Videos, die die inneren Abläufe von RCT tiefgehend analysieren