>I didn't know there was a fork and I'm excited to look into it
OpenRCT2 isn't a fork, it's like OpenTTD, a recreation.
Go look at GDC's Classic Game Postmortems. They have tens of videos of the people who built famous games from the 80s and 90s who often go into technical details of how they do it. For example, Robotron goes into how the code works.
It's remarkably familiar. They basically built object oriented programming and classes using convention only. You treat every actor you want to work with as a chunk of memory with standard layout that includes pointers for behavior and slots for state, and you just try really hard to only operate on the right "Types" at the right places. From there you have your standard game loop of "Get input, update all Actors, render, loop"
The Pitfall postmortem is wonderful. The Atari 2600 had roughly zero RAM to work with, and barely any cartridge space to hold your game. To make their large, somewhat open world, they made each screen built off just a few parameters, and created a bidirectional psuedorandomish function that would generate the parameters on a cycle, giving you a connected map space!
What language is this article talking where compilers don't optimize multiplication and division by powers of two? Even for division of signed integers, current compilers emit inline code that handles positive and negative values separately, still avoiding the division instruction (unless when optimizing for size, of course).
> Imagine a programmer asking a game designer if they could change their formula to use an 8 instead of a 9.5 because it is a number that the CPU prefers to calculate with. There is a very good argument to be made that a game designer should never have to worry about the runtime performance characteristics of binary arithmetic in their life, that’s a fate reserved for programmers
Numeric characteristics are absolutely still a consideration for game designers even in 2026, one that influences what numbers they use in their game designs. The good ones, anyways. There are, of course, also countless bad developers/designers who ignore these things these days, but not because it is free to do so; rather, because they don't know better, and in many cases it is one of many silent contributing factors to a noticeable decrease in the quality of their game.
I was reminded of the factorio blog. That game's such a huge optimization challenge even by today's standards and I believe works with the design.
One interesting thing I remember is if you have a long conveyor belt of 10,000 copper coils, you can basically simplify it to just be only the entry and exit tile are actually active. All the others don't actually have to move because nothing changes... As long as the belts are fully or uniformly saturated. So you avoid mechanics which would stop that.
> The same trick can also be used for the other direction to save a division:
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.
(emphasis mine)
Not at all true. Assuming the types are such that >> is equivalent to /, modern compilers will implement division by a power of two as a shift every single time.
> When reading through OpenRCT2’s source, there is a common syntax that you rarely see in modern code, lines like this:
> NewValue = OldValue << 2;
I disagree with the framing of this section. Bit shifts are used all the time in low-level code. They're not just some archaic optimisation, they're also a natural way of working with binary data (aka all data on a computer). Modern low-level code continues to use lots of bit shifts, bitwise operators, etc.
Low-level programming is absolutely crucial to performant games. Even if you're not doing low-level programming yourself, you're almost certainly using an engine or library that uses it extensively. I'm surprised an article about optimisation in gaming, of all things, would take the somewhat tired "in ye olde days" angle on low-level code.
Warcraft 1 (1994), Warcraft 2 (1995), and StarCraft (1998) all use power-of-2 aligned map sizes (64 blocks, 128 blocks, and 256 blocks) so the shift-factor could be pre-computed to avoid division/multiplication, which was dang slow on those old 386/486 computers.
Each map block was 2x2 cells, and each cell, 8x8 pixels. Made rendering background cells and fog-of-war overlays very straightforward assembly language.
All of Warcraft/etc. had only a few thousand lines of assembly language to render maps/sprites/fonts/fog-of-war into the offscreen buffer, and to blit from the offscreen buffer to the screen.
The rest of the code didn't need to be in assembly, which is too time-consuming to write for code where the performance doesn't matter. Everything else was written in portable assembler, by which I mean C.
Edit:
By way of comparison, Blackthorne for Super Nintendo was all 85816 assembly. The Genesis version (Motorola 68000) and DOS version (Intel 80386) were manually transcribed into their respective assembly languages.
The PC version of Blackthorne also had a lot of custom assembler macros to generate 100K of rendering code to do pixel-scrollable chunky-planar VGA mode X (written by Bryan Waters - https://www.mobygames.com/person/5641/bryan-waters/).
At Blizzard we learned from working on those console app ports that writing assembly code takes too much programmer time.
Edit 2:
I recall that Comanche: Maximum Overkill (1992, a voxel-based helicopter simulator) was written in all assembly in DOS real mode. A huge technical feat, but so much work to port to protected mode that I think they switched to polygon-rendering for later versions.
> By way of comparison, Blackthorne for Super Nintendo was all 85816 assembly
Weren't almost all console games up to that era written in assembly? What high level languages were used? I recall hearing many Atari 7800 (?) games were written in Forth? May be mistaken.
Is there a place to find stories of recent game optimization? What's most ridiculous on like quick inverse square route. As someone who spent way too much time vraying in prior life, I still can't believe we got real time ray tracing.
I have to wonder how much of the original assembly source looked a lot more succinct than whatever's in OpenRCT due to the use of macros. Looking up his gameography on Mobygames, Chris had been writing stuff since 1984 when RCT came out in 1999, it's hard to imagine he was still writing every single opcode out by hand given that I had some macros in the assembler I was fooling around with on my c64 back in the eighties.
On huge games produced by large game studios, I wonder if the idea of using a real world technical challenge as a "feature" within the game is considered genius? Consider a coder and a game designer who are on different teams and don't attend the same meetings.
But if you look at creative writing, story arcs are all about obstacles. A boring story is made interesting by an obstacle. It is what our protagonist needs to overcome. A one-man-band game dev who simultaneously holds the story and the technical challenge their head, might spot the opportunity to use a glitch or limitation as, I dunno, a mini game that riffs on the glitch.
Compilers won't do multiplication by power of two to bit shift for you ? I remember reading in ~2000: the only thing writing a<<2 instead of a/4 will do is make your compiler yawn
45 comments
[ 3.4 ms ] story [ 71.3 ms ] threadThe more I actually started digging into assembly, the more this task seems monumental and impossible.
I didn't know there was a fork and I'm excited to look into it
OpenRCT2 isn't a fork, it's like OpenTTD, a recreation.
Go look at GDC's Classic Game Postmortems. They have tens of videos of the people who built famous games from the 80s and 90s who often go into technical details of how they do it. For example, Robotron goes into how the code works.
It's remarkably familiar. They basically built object oriented programming and classes using convention only. You treat every actor you want to work with as a chunk of memory with standard layout that includes pointers for behavior and slots for state, and you just try really hard to only operate on the right "Types" at the right places. From there you have your standard game loop of "Get input, update all Actors, render, loop"
The Pitfall postmortem is wonderful. The Atari 2600 had roughly zero RAM to work with, and barely any cartridge space to hold your game. To make their large, somewhat open world, they made each screen built off just a few parameters, and created a bidirectional psuedorandomish function that would generate the parameters on a cycle, giving you a connected map space!
"Interview with RollerCoaster Tycoon's Creator, Chris Sawyer (2024)" https://news.ycombinator.com/item?id=46130335
"Rollercoaster Tycoon (Or, MicroProse's Last Hurrah)" https://news.ycombinator.com/item?id=44758842
"RollerCoaster Tycoon at 25: 'It's mind-blowing how it inspired me'" https://news.ycombinator.com/item?id=39792034
"RollerCoaster Tycoon was the last of its kind [video]" https://news.ycombinator.com/item?id=42346463
"The Story of RollerCoaster Tycoon" https://www.youtube.com/watch?v=ts4BD8AqD9g
And this folks is why an optimizing compiler can never beat sufficient quantities of human optimization.
The human can decide when the abstraction layers should be deliberately broken for performance reasons. A compiler cannot do that.
Numeric characteristics are absolutely still a consideration for game designers even in 2026, one that influences what numbers they use in their game designs. The good ones, anyways. There are, of course, also countless bad developers/designers who ignore these things these days, but not because it is free to do so; rather, because they don't know better, and in many cases it is one of many silent contributing factors to a noticeable decrease in the quality of their game.
> NewValue = OldValue >> 3;
You need to be careful, because this doesn't work if the value is negative. A
I was reminded of the factorio blog. That game's such a huge optimization challenge even by today's standards and I believe works with the design.
One interesting thing I remember is if you have a long conveyor belt of 10,000 copper coils, you can basically simplify it to just be only the entry and exit tile are actually active. All the others don't actually have to move because nothing changes... As long as the belts are fully or uniformly saturated. So you avoid mechanics which would stop that.
(emphasis mine)
Not at all true. Assuming the types are such that >> is equivalent to /, modern compilers will implement division by a power of two as a shift every single time.
… oh wait, nvm. Don’t preoptimize!
I really wish I could see the source code.
> NewValue = OldValue << 2;
I disagree with the framing of this section. Bit shifts are used all the time in low-level code. They're not just some archaic optimisation, they're also a natural way of working with binary data (aka all data on a computer). Modern low-level code continues to use lots of bit shifts, bitwise operators, etc.
Low-level programming is absolutely crucial to performant games. Even if you're not doing low-level programming yourself, you're almost certainly using an engine or library that uses it extensively. I'm surprised an article about optimisation in gaming, of all things, would take the somewhat tired "in ye olde days" angle on low-level code.
Each map block was 2x2 cells, and each cell, 8x8 pixels. Made rendering background cells and fog-of-war overlays very straightforward assembly language.
All of Warcraft/etc. had only a few thousand lines of assembly language to render maps/sprites/fonts/fog-of-war into the offscreen buffer, and to blit from the offscreen buffer to the screen.
The rest of the code didn't need to be in assembly, which is too time-consuming to write for code where the performance doesn't matter. Everything else was written in portable assembler, by which I mean C.
Edit:
By way of comparison, Blackthorne for Super Nintendo was all 85816 assembly. The Genesis version (Motorola 68000) and DOS version (Intel 80386) were manually transcribed into their respective assembly languages.
The PC version of Blackthorne also had a lot of custom assembler macros to generate 100K of rendering code to do pixel-scrollable chunky-planar VGA mode X (written by Bryan Waters - https://www.mobygames.com/person/5641/bryan-waters/).
At Blizzard we learned from working on those console app ports that writing assembly code takes too much programmer time.
Edit 2:
I recall that Comanche: Maximum Overkill (1992, a voxel-based helicopter simulator) was written in all assembly in DOS real mode. A huge technical feat, but so much work to port to protected mode that I think they switched to polygon-rendering for later versions.
Weren't almost all console games up to that era written in assembly? What high level languages were used? I recall hearing many Atari 7800 (?) games were written in Forth? May be mistaken.
https://youtu.be/twU1SsFP-bE
He has lots of videos that are deep dives into how RCT works and how things are implemented!
At first this sounds like a strange technical obscurity"
Do we not know binary in 2026? Why is this a surprise to the intended audience?
But if you look at creative writing, story arcs are all about obstacles. A boring story is made interesting by an obstacle. It is what our protagonist needs to overcome. A one-man-band game dev who simultaneously holds the story and the technical challenge their head, might spot the opportunity to use a glitch or limitation as, I dunno, a mini game that riffs on the glitch.
Reminds me of blood moons in Zelda https://www.polygon.com/legend-zelda-tears-kingdom/23834440/...