The gold standard of optimization: A look under the hood of RollerCoaster Tycoon
Recorded: March 22, 2026, 10 p.m.
| Original | Summarized |
The gold standard of optimization: A look under the hood of RollerCoaster Tycoon – Larst Of Us Skip to content Larst Of Us AboutBlogroll Bluesky The gold standard of optimization: A look under the hood of RollerCoaster Tycoon Due to some lucky circumstances, I recently had the chance to appear in one of the biggest German gaming podcasts, Stay Forever, to talk about the technology of RollerCoaster Tycoon (1999). It was a great interview, and I strongly recommend to listen to the whole episode here, at least if you speak german. If not, don’t worry—this article covers what was said (and a little more). RollerCoaster Tycoon and its sequel are often named as some of the best-optimized games out there, written almost completely in Assembly by their creator, Chris Sawyer. Somehow this game managed to simulate full theme parks with thousands of agents on the hardware of 1999 without breaking a sweat. An immensely impressive feat, considering that even nowadays a lot of similar building games struggle to hit a consistent framerate. So how did Chris Sawyer manage to achieve this? Written by (very) dedicated fans, OpenRCT2 manages to reimplement the entirety of RollerCoaster 1&2, using the original assets. Even though this is NOT the original source code, especially in its earlier versions, this re-implementation is a very, very close match to the original, being based on years of reverse engineering. Note that by now, OpenRCT2 contains more and more improvements over the original code. I’ll note some of those changes as we come across them. Different money values in the code use different data types, based on what the highest expected value at that point is. The variable that stores the overall park value, for example, uses 4 bytes since the overall park value is expected to use quite high numbers. But the adjustable price of a shop item? This requires a far lower number range, so the game uses only one byte to store it. Note that this is one of the optimizations that has been removed in OpenRCT2, which changed all occurrences to a simple 8-byte variable, since on modern CPUs it doesn’t make a performance difference anymore. NewValue = OldValue << 2; Thanks to operator overloading, the ‘<<’ operator can mean a lot of things in C++. What the line effectively does is the same as what most coders would write like this: NewValue = OldValue * 4; What the ‘<<’ operator does here is called bit shifting, meaning all the bits that store the value of the variable are shifted to the left, in this case by two positions, with the new digits being filled in with zeros. Since the number is stored in a binary system, every shift to the left means the number is doubled. NewValue = OldValue >> 3; This is basically the same as NewValue = OldValue / 8; RCT does this trick all the time, and even in its OpenRCT2 version, this syntax hasn’t been changed, since compilers won’t do this optimization for you. This might seem like a missed opportunity but makes sense considering that this optimization will return different results for underflow and overflow cases (which the code should avoid anyway). From a tech point of view, this design, however, is basically a worst case scenario. Pathfinding is an expensive task, and running it for potentially thousands of agents at the same time is a daunting prospect, even on modern machines. Yep, every time a park guest complains about not being able to find the exit, this is basically the Pathfinder telling the game that there might be a path, but for the sake of performance, it won’t continue searching for it. The solution, again, is just to bypass the technical challenge altogether. The guests in RCT don’t collide with each other, nor do they try to avoid each other. In practice, even thousands of them can occupy the same path tile: Share on Facebook (Opens in new window) Share on LinkedIn (Opens in new window) Share on Mastodon (Opens in new window) More posts to read The gold standard of optimization: A look under the hood of RollerCoaster Tycoon The curious case of Unreal’s slow asset reimport notification I tried to use Unreal on Linux… it’s rough How to run a city builder on 16 MHz Speeding up the Unreal Editor launch by … not opening 5500 files? Speeding up the Unreal Editor launch by … not spawning 38000 tooltips? Profiling without Source code – how I diagnosed Trackmania stuttering Upgrading Unreal’s Static Mesh Editor …again! How “deleting multiplayer from the engine” can save memory Next Page Leave a comment Cancel reply Δ Type your email… Mastodon
Loading Comments...
Write a Comment... Email (Required) Name (Required) Website Comment Reblog Subscribe Subscribed Larst Of Us Join 40 other subscribers
Sign me up Already have a WordPress.com account? Log in now. Privacy
Larst Of Us Subscribe Subscribed Sign up Copy shortlink Report this content View post in Reader Manage subscriptions Collapse this bar %d |
RollerCoaster Tycoon (RCT), developed by Chris Sawyer, stands as a landmark achievement in game optimization, particularly notable for its consistent performance despite simulating thousands of agents within a theme park environment – a feat that continues to challenge modern game development. This article, stemming from an interview with Chris Sawyer on the German podcast “Stay Forever,” delves into the key techniques employed to achieve this remarkable level of optimization, primarily through a combination of low-level coding, aggressive optimization strategies, and a uniquely designed game system. A central element of RCT’s success was Chris Sawyer’s utilization of Assembly language, a practice largely abandoned by the game development industry at the time. Assembly provided a significantly higher degree of control over hardware resources compared to higher-level languages like C or C++, resulting in performance advantages that were considerably more impactful than they would be in contemporary development. While other games, such as Doom, had utilized Assembly for specific sections, RCT was, according to the interview, one of the last major games developed almost entirely in this manner. The compiler technologies of the late 1990s were less sophisticated than those available today, meaning manual optimizations within Assembly were often substantially more impactful. Alongside Assembly coding, the game’s code was systematically optimized. The exploration of OpenRCT2, a 100% compatible reimplementation of the original game, provides valuable insight into these optimizations. OpenRCT2, developed by dedicated fans, reflects years of reverse engineering and represents an incredibly close match to the original code, particularly in its more recent iterations. This allows for examination of the specific techniques employed. One striking example is the handling of monetary values. The game utilizes different data types based on the expected value range, conserving memory and improving computation speed. For instance, the overall park value is stored in a 4-byte variable, while shop items require only a 1-byte variable, a choice now largely irrelevant due to modern CPU capabilities. However, this optimization has been removed in OpenRCT2, utilizing a single 8-byte variable, demonstrating how performance considerations evolve with technological advancements. Another key optimization involved the substitution of traditional math operations with bitshifting. The code employs the left-shift operator (`<<`) for multiplication by powers of two and the right-shift operator (`>>`) for division by powers of two. This circumvents the performance overhead associated with standard multiplication and division operations, which, while faster in modern processors, weren’t as efficient in 1999. This technique highlights the meticulous attention to detail and the understanding of hardware architecture that Sawyer and his team exhibited. It’s important to note that compilers no longer perform this optimization automatically, necessitating its inclusion within the original code. Furthermore, the game’s design choices were intrinsically linked to its performance. Chris Sawyer’s approach emphasized a “game design for performance” philosophy. A prime example is the guest behavior system. Rather than implementing a complex, computationally intensive pathfinding system for every guest, the game employs a deliberately “broken” approach: guests wander around the park randomly, stumbling upon attractions by chance. This dramatically reduces the processing burden on the system, preventing performance slowdowns and frame rate drops, particularly when numerous guests are present. This system isn’t simply a design flaw; it’s a strategic optimization. The pathfinding system itself incorporates safety measures to prevent frame spikes. The pathfinder has a built-in limit on the maximum distance it will traverse to find a path, and if a path isn’t found within that limit, the search is aborted. This limitation is adjustable—mechanics and guests who have acquired a map of the park receive increased search allowances. This clever manipulation demonstrates how design choices can directly influence performance and even subtly shape gameplay. Crowded park management also exemplifies optimization. The game bypasses the complex task of implementing agent collision or avoidance systems, allowing thousands of guests to occupy the same path tiles simultaneously. This decision is informed by the realization that the computational cost of resolving these collisions would severely impact performance. However, the game includes a system to monitor guest happiness, triggering complaints when guests feel overwhelmed, requiring the player to strategically manage the layout to avoid bottlenecks. The calculations for this system are significantly faster than traditional collision detection methods, showcasing a deliberate trade-off between technical complexity and performance. These optimizations weren't solely the product of a single programmer; the game benefited from the collaborative efforts of additional developers, including Simon Foster (graphics) and Allister Brimble (sound). Chris Sawyer’s simultaneous role as both programmer and game designer allowed for a deeply integrated design-performance feedback loop, enabling critical decisions to be made with a nuanced understanding of the game’s technical limitations. In essence, RollerCoaster Tycoon achieved its legendary status through a masterful blend of low-level coding, intelligent design choices, and a meticulous attention to detail. The techniques employed – from bitshifting to random guest behavior – underscore a profound understanding of hardware architecture, game design principles, and the importance of collaboration. OpenRCT2 continues to build upon these optimizations, solidifying RCT's legacy as a benchmark for game optimization. |