Via Augury I found out about .kkrieger, a first-person shooter game which is only 97k in size. That means the entire game, sound effects, graphics, code, and everything, all within 97k. That is preposterously small, yet the game still looks quite good and at first glance it can pass for a cutting-edge shooter.
Remember these things?
Yeah. That disk holds about 370k, which means this game could fit on this disk three times and still have “plenty” of space left over. Unreal Tournament 2004 comes on 6 CDs. If it came on floppies, you would need a truck loaded with about 10,000 floppy discs. To put it another way, Unreal Tournament is around Forty Thousand times larger than .kkreiger.
So this game is small. Ridiculously small. But what makes games like UT 2004 so big in the first place? Take a look at the gun you see in the screenshot.
So how big would that gun be if we had to store it on disk?
Let’s assume that it’s not quite as detailed as it looks. (I think bump-mapping is adding a lot of the surface detail.) Let’s say the gun is 100 polygons and 150 verticies. The weapons in today’s games are much more detailed, but let’s assume we’re being frugal:
Each vertex needs at minimum 3 spatial values (x, y, and z), two texture-mapping values, and three normal vector values (for lighting). That’s a total of 8 values per vertex. Normally each of those values is 4 bytes, so we need 4 bytes x 8 values x 150 verticies = 4,800 bytes. Each polygon is a triangle which connects 3 vertices. So assuming each index is 2 bytes we need 2 bytes x 3 indexes x 100 polygons = 600 bytes. The texture is made up of two images: the color map and the bump-map. For a texture on something that close to the camera, you probably can’t get away with anything less than 128 x 128 pixels. Each pixel is three values, red, green, and blue. (for the bump map, these color values are converted into spatial values). Each value is one byte. 1 byte per value x 3 values per pixel x 128 pixels wide x 128 pixels high x 2 images = 98,304 bytes.
So even if we are very conservative, our total size for the gun is 4,800 + 600 + 98,304 = 103,704 bytes, or 101k!
So the gun you see there in the screenshot would be about 101k, which is bigger than the entire kkreiger program! And yet within the 97k of the program it has not just one gun but several, plus enemies to fight, rooms to fight in, and music to listen to while you’re fighting. All of that plus the code that drives the game fits within a space smaller than the size of just one weapon!
As the original article points out, this is done using procedural methods. Instead of storing the 101k gun and its textures, just come up with some code that can generate a gun on the fly. This takes away a great deal of artist freedom, as you can no longer design a gun just the way you want, you can only control the parameters used to generate it. Remember spirograph? It’s a bit like that. You can’t just draw anything you want, but you CAN draw pleasing shapes and patterns with a great deal of precision. In the applet I just linked, you see that I can re-create anything you draw as long as you send me the exact settings you used. If you want to show me an image you made, instead of sending me a screenshot, you could send the 3 numbers you chose and I would be able to re-create what you made by simply plugging in those same values.
So, instead of storing a 101k gun with your program, you can write a gun-generating spirograph, find some numbers that look good, and then plug those numbers in when the program runs. That’s the tradeoff: This game has a long loading time, because it’s sitting there cranking numbers through the various generators, making guns and monsters and rooms.
This is a fun demonstration of what can be done with procedural objects, although it has a lot of implications for the future of game development. I’m not talking about saving hard drive space, though. This sort of thing is far more useful for combating the growing cost of content creation, which I’ll leave for the next post.