There is a lot that goes into making video games, in a programming sense. Video games are taxing in ways that most programmers aren’t used too, and they force us to (in a good way) to make sure that are skills are sharp. No matter if your game is an 8-bit throwback like Shovel Knight or a video-card fryer like Metal Gear Solid 5, there are some things you’re going to need to know if you want to have the programming chops to be a game coder. This week we’re going to talk about, quite possibly the most important facet of any game (or program for that matter), memory management.
If that phrase doesn’t immediately invoke a piece of innate programming knowledge then you, my friend, have some studying to do. Don’t feel too bad though, most modern programming languages are meant to obfuscate things like garbage collection away from the programmer, making it “easier” for them to focus on coding. If you don’t know what garbage collection is, it’s the act of freeing the memory your finished using. When an enemy dies, for example, all of the variables that dictated things like her health, position, AI patterns, etc… can all be thrown in the garbage. That memory space can then be used for a new enemy, or something else.
In the worst case, not addressing garbage collection causes a memory leak, which means that your program will pile up all of this memory that it thinks it’s using (but really isn’t) until there is no more left and the whole program goes kaput. That’s actually a good thing though, because in that situation you’ll likely be forced to find your mistake. The far more sinister symptom of bad memory management is simply bad performance. Sure, languages like C# will dispose of your objects for you most of the time, but do you know exactly when that’s happening, or how? These questions may not be terribly important when it comes to a small business app that used by 20 people a day, but if you’re writing a game that needs every single byte of memory available, garbage collection becomes a really important issue.
It’s not necessarily important to do the garbage collection yourself, but it’s critical that you understand how and why it’s happening, and that you don’t ignore the principle altogether. As I said, garbage collection may seem trivial in many applications but games are simply not one of them.
Understanding variable types goes hand-in-hand with understanding garbage collection. It’s all about the memory. How many bytes are in a 32-bit integer? What is the difference between and signed and unsigned 32-bit integer? What is the minimum and maximum value for each of those types? These questions are important because many times we as programmers take our memory space for granted (just like with garbage collection). If you need to hold a true/false value you don’t need a 32-bit integer. You need a boolean. Why? A boolean variable consumes only one byte of memory vs. a 32-bit integer’s 4 bytes. What’s more, you only need a value of 0 or 1 so all of that other address space that’s consumed by the integer is completely useless.
One byte vs. four bytes certainly isn’t a lot, but those bytes add up very quickly when game logic gets complex. Enemies with lots of variables can take up huge amounts of space and if 75% of that space is consumed by memory that’s not being used simply because you didn’t use the write variable type, that’s bad form.
Beyond the simple example of int vs. bool are much more complex issues of memory management. Understanding the difference between a fixed length array and a hash-table, a string and a character array, and even the difference between a floating point value and an integer. They all have uses and misuses and using the right types in the right place can be the difference between a game that performs like a champ and one that performs like a loser.
Understand your platform.
It’s no small feat to develop a well performing game these days in part because there are so many platforms with so many different considerations. Take an iPhone 6 for example; it has 1GB of DDR3 RAM. The XBox One, by contrast, has 8. The PS4 also has 8, but it has GDDR5 RAM. The average gaming PC has anywhere between 8 and 64gb of RAM that can come in one of many different variations. With regard to all of those systems there are concerns as to how much RAM can be used by the game itself and how much is allocated for the OS. In the case of a PC and a a phone (and to a growing degree, consoles) there is no way to control how many other applications a user may be running while playing your game.
All of this nonsense amounts to the same thing; keep your memory footprint as low as you can with the most well crafted code that you can. You’re never going to be able to account for all of the different quirks of any single system, let alone a multitude of them at the same time, so code with the lowest common denominator in mind and work up from there.
This may be nothing more than a personal anecdote, but I’ve, on multiple occasions, found huge performance increases in the nooks and crannies of my code where I thought nothing interesting was happening. Turning one int into a bool can save thousands of bytes of RAM, and understanding your platform means understand just what those bytes are worth to you.