NESert Golfing: making an NES golf game


I made a game called NESert Golfing. If you haven’t played it, there’s a link in the video description where you can download the ROM, but I’d like to talk about why I made it, and how. I’m very interested in the NES as a platform for games, and I often think about how well other games might translate to it. I ran across Desert Golfing, made by Justin Smith in 2014, and I really enjoyed how much fun I was getting from a very simple concept: it’s just a ball and a hole on some two-dimensional sandy hills, endlessly repeating in infinite variation. If you want to play the original Desert Golfing, there’s a link in the description. It’s got iPhone and Android versions that are pretty great for playing on the toilet. So playing this game, I went through my usual thoughts about how it could work on the NES. I liked that it was a small scope, with not a lot of design work, no levels to build, not much art, no music… It seemed like a project I could get done in a short period of time. I also tried to think of NES games based on physical simulations like this, and I really couldn’t think of many. Lunar Pool is the closest one that comes to mind. Finally, it struck me as something that would be well suited to a mouse interface, and that probably sounds like a weird thing to say for the NES, which never had an official mouse peripheral. …but there’s a homebrew NES game called Thwaite that was made by Damian Yerrick in 2011. It’s overtly a clone of Missile Command, but it was also an NES game you could play with the Super NES mouse! As it turns out, the NES and Super NES had nearly identical protocol for reading a controller. Even though the plugs are a different shape, the signals going over the wires are very compatible. With a simple adapter you can connect SNES controllers to your NES, and they work well with most games. The mouse can use the same adapter too, but of course none of the original NES games would have had support for it. A few years ago I’d tried Thwaite, but I didn’t have a SNES mouse or an adapter, and there weren’t even any NES emulators that could emulate this unorthodox peripheral, so I decided to write some emulator support for it, which I contributed to FCEUX. Once I had that working I was surprised by how suitable it was! Thwaite was good with the gamepad, but it really shines with a mouse in hand. Since then I’ve acquired an SNES to NES adapter, and a nice clone of the SNES Mouse by Hyperkin, which I actually like better because it uses more sensitive optical technology, compared to the original ball mouse. I’d been looking for an excuse to put it to use, and this golf project seemed like a perfect fit. Getting this to work was relatively easy. Most of it was already well documented by the emulation community. I wrote a test ROM to get some clarification on the finer details, but overall it was surprisingly straightforward to interface with. While I was working out the mouse details, I also decided to make it multiplayer. Even though Desert Golfing was a very solitary experience, I thought it could be fun to play with friends, so I added some support for 4-player adapters too. You can share a controller if you’ve only got 1 or 2, but if you’ve got a multitap everyone can have their own. Only one mouse, though, there’s some technical reasons that made that too tricky. Another thing I wanted was to get away from the tile grid of the NES. So many games on this platform have a distinctive boxy look, so I try to find ways to get around that. I have a whole other video on this topic, but the NES cartridge interface has an option to use rewritable RAM for graphics tiles, instead of a read-only ROM chip, which was more common, but with RAM, instead of having to build the slopes and valleys to fit on a grid, I could go pixel by pixel with slopes of any angle and height. There were still some restrictions to deal with, though. I needed to fill up two screens wide with these rendered tiles, and the NES only really has enough background tile memory to fill up about a quarter of the screen with unique tiles. I restricted the maximum slope so that across an 8-pixel span of one tile, they could only rise or fall by 4 tiles. Above and below, I could reuse solid tiles to fill the sky and ground, but this means I can’t really have vertical walls, or the little overhangs that Desert Golfing did, but this helped a lot with the NES implementation, so I thought it was an acceptable trade. I also took advantage of the limited colour scheme, sacrificing extra colours to double the number of tiles I could use. Because NES tiles actually have 4 colours, not just 2, I can stick two slopes on top of each other by using special palettes. The four colours here correspond to empty, slope 1, slope 2, and both at once. I also used the same technique to fit the title image and font set together in the same space. Every time you play the game, an entirely different set of randomly generated holes will appear. This is a little bit different from Desert Golfing, which did have procedurally generated holes, but hole 5 was always the same hole 5 for anyone that played. It also saved your progress, which made it practical to keep playing new holes, but on the NES there was no built in hard disk like modern platforms. Games with a save had to include a battery and memory inside the cartridge, which made it more costly to manufacture. I didn’t feel like a battery save would fit with the NES tradition here, at least not for a small game like this, so instead I thought it was better to always start from hole 1, but give you new courses every time you play. The actual holes aren’t specifically generated to be hard or easy. I have two parameters that control the generator that I change over time hoping to provide some variety, but they correspond to “bumpiness” and “steepness”. Usually what makes a hole easy is when the cup lies in a valley, and conversely the hard ones put it on a sharp hilltop. The hardest holes are usually due to weather. This is another thing that Desert Golfing didn’t have, but I like the affect of wind in golf games, and I also enjoy rain and snow, so I put them into NESert Golfing as a visual indicator of how the wind is blowing, so you can adjust your shot to take it into account. The basic physics simulation in this game is a ball bouncing off a flat surface. This is probably the one thing here that was least suited to the NES, and I’ll get into why that is in a moment, but first I’ll describe the algorithm. We start by moving the ball. It has a position, and a velocity. These are both represented by a two-dimensional pair of numbers called a Vector. The velocity is just added to the position each frame. With a 2D vector this means Velocity X is added to Position X, and Velocity Y is added to Position Y. To make the ball fall to the ground, we have a third vector for gravity, which gets added to the velocity each frame. This simple process of adding acceleration, to velocity, to position is sometimes known as Euler Integration, but it’s an effective way to generate a nice parabolic arc of motion like this. The second part is figuring out when the ball hits the line of the surface. We determine this by projecting the position of the ball onto a line perpendicular to the surface, called its Normal. This gives us a 1D value that tells us how close it is to the centre of the ball. If it ever gets closer than the ball’s radius, we have a collision! …and for a collision there are two things to resolve: First the ball has to bounce off, instead of continuing to travel deeper inside the surface. For this we need to reflect the ball’s velocity off that surface, like a mirror. To do this we do more projection. We have the surface Normal vector from before, but also its perpendicular Tangent vector that points along the surface. By projecting the velocity onto these two vectors, we transform it into the perspective of the surface. From the surface’s perspective, it’s now very easy to see how to reflect the velocity to bounce off: you just make the vertical part negative. Once that’s done, do the reverse projection, taking the surface-relative velocity back into the original space of the world, which finally tells us what the reflected velocity vector should be. The second thing to resolve is the ball’s position. At this point we’ve corrected where it will go, but we haven’t fixed the problem that the ball is stuck inside the ground. To get rid of this overlap we need to push the ball back. Ideally we could subdivide the frame, find the exact point in time where it touched the surface, do the bounce there, and then finish the rest of the frame. Unfortunately, the NES is not very good at arbitrary subdivision, so I take an approximation here. It was more practical to just push it out along the surface normal. Not quite where it belongs, but it was close enough for this game. So that’s the basic collision resolution, but the sticky point here is multiplication. The math for each of these projections requires several multiply steps. On a modern platform, we have floating point numbers, and CPU instructions that can multiply them for us. On the NES, we don’t have either of these things. Even the instructions we do have only work on 8-bit numbers, which are far too imprecise for this task. So… we have to build up more precise numbers out of 8-bit blocks, and we have to build up a synthetic multiplication routine out of simpler instructions, and instead of floating point we use fixed-point numbers. Basic binary representation covers the integer whole numbers, but when you need values between the whole numbers, we need the binary equivalent of a decimal point. Modern hardware conveniently supports this with “floating point” instructions that automatically place this point where it’s needed most. However, without hardware support for it, simulating floating point takes way too much extra computation. On a lot of older hardware, it’s more practical to use what is called a “fixed point”, which is like always having the same number of decimal places. Fixed point is also the same as pre-multiplying a number with constant factor. If you had 3.14 with a decimal point, you could represent all of its digits by multiplying by 100. 314 is now just an integer, and you can use it with all of your instructions for integer arithmetic. In binary representation, this works very much the same, but you mulitply by a power of 2 rather than a power of 10. In particular, a lot of the values in NESert Golfing are stored with 8 bits of fixed point, which is like a pre-multiplication by 256. The projection calculations rely on multiplying two fixed point numbers, and when you multiply fixed point numbers together, there’s one more thing you have to account for: both numbers are pre-multiplied, which means that second pre-multiplication carries through to the result. For instance, if you had 2 decimal points on each number going in, the result has 4 decimal points. Correcting this is very easy, though: we just drop the two least significant digits to get back to our original data size. We’re losing precision here, of course, but it’s a manageable loss. Every computer physics simulation has to deal with precision issues somewhere. So with our fixed point representation, all we need now is an integer multiplication routine. How can we do this with the NES’ limited instruction set? You have addition, and you have a binary shift. The binary shift is like multiplying by 2, which is easy for the hardware in the same way it’s easy to multiply by 10 in decimal. Just add a zero and you’re ready to go. Synthesizing a full multiplication out of the add and shift instructions is pretty much the same way you were probably taught to do long-multiplication in school. Multiply each digit of the second number by the first, and shift over one column each time, then just add up the results. The main difference here is that the numbers are binary 1s and 0s instead of decimal digits from 0 to 9. Because of all the steps involved, this is very slow, and I think this is the main reason that physics simulation is rare on the NES. Even for just one ball here, resolving a collision takes up about half the frame. I wanted this game to run at a solid 60 frames per second, so there wasn’t much room for added complexity. There are a few other liberties I had to take for the sake of performance. Where friction should slow down the ball, or when trapped in a valley between two opposing slopes, the behaviour here isn’t quite ideal but I think the approximations I’ve made are acceptable. I thought it was maybe fun that with some experience you can learn to get the ball to come to rest on the side of a steep hill. So I’ve probably said enough here about how this game was made. If you’re interested in learning more, I’ve made the source code available, and you can have a look for yourself at all the finer details. This was mostly writen in the C programming language, though there were a handful of critical routines that I wrote directly in assembly language for performance reasons. In particular the fixed point multiply, the pixel packing part of the terrain rendering, and the snow and rain animation all needed some extra efficiency. Anyhow, that’s NESert Golfing. If you want to play it, check the video description for a link to a free download. If you’d like a version you can play on your phone, I highly recommend getting the original game Desert Golfing, which I’ve also linked below. It is very reasonably priced, and it’s surprisingly addictive and a lot of fun. Thanks for listening, and I hope you enjoy NESert Golfing.

Leave a Reply

Your email address will not be published. Required fields are marked *