So you want to be a video game programmer? – part 5 – The Method

…CONTINUED from PART 4. Or start at Part 1.

This post is presents an algorithm of sorts for learning to program. It applies not only to the fundamentals, but to all aspects, including the acquisition of small component skills. Thirty years after learning, I still follow the same basic procedure. To tell the truth, modified, it works for leaning most things.

Step 1: Goal. Invent some manageable goal that excites you (in a later context as a profession “excites” is often replaced/supplemented by “need”). My first program was a text-based dungeon master (see here). If you want to be a video game programmer, there’s nothing better than a game. If it’s one of your first programs, make it damn simple. Copy some REALLY REALLY old and simple game like anything from before 1981 (PongBreakout, etc.). Truth be told, using text only for a couple weeks/months might not be a bad idea. Graphics just complicate matters. They’re awesome — and you’ll need them soon enough — but first the fundamentals, like variables, flow of control, scope, etc. Any individual task should take no more than a few days. If your goal is bigger than that, subdivide.

Step 2: Environment. All programming is done in the context of some environment, and you must learn about it. You need to start with a simple one. In my case it was mostly AppleSoft BASIC. For learning interpreted is good. Some decent starter environments today are Python, Ruby, Flash, Lua. DO NOT START WITH A LANGUAGE LIKE C. I will elaborate on this environment question in a separate full post, as it’s a large topic and highly religious for programmers.

Step 3: Research. This means reading. If you don’t like to read, either learn to or find yourself a new career. I’m serious. Reading separates the Neo Cortexs from the gibbering marsupials. I’m serious. Be a New Cortex. Your love of reading must be so extreme that you can stomach slogging through 900 page Library Reference Manuals (maybe not at first). Programming is full of details.

Step 4: Theory. Get out a pad of paper, a text file, Evernote, or whatever. Design what you are going to do. Later, you might or might not skip this step (and do it in your head), but it’s useful for the beginning programmer. You don’t need to write out the entire program, but you should design your data-structures and modules or functions. If it’s one of your first programs, you should hardly HAVE data-structures. You might instead write down the modes and loose flow chart between them.

Step 5: Code. Actually try coding your program. This is best done in an iterative way. My advice is generally to start with creating your core data-structures, and then the functions or methods that support them. Test each of these individually. Interpreted languages with a listener are the best because you don’t have to write test suites, but can just test the components as you go at the listener. Time spent debugging individual functions and groupings (say all the methods that belong to a data-structure) pays for itself 100-fold. I still do this. The less code you are testing, the easier it is to spot and find bugs. If you know that your functions are reliable (or semi-reliable) they provide robust building blocks to construct with.

Step 6: Debug. See above in “code” because they are heavily intertwined. Coding and debugging happens together in small loops. Again. The less NEW code you have to debug, the better. Debugging is hard for novices. Do not write an entire big program and debug it all at once. If you are using a language that syntax checks, check each function after you have written it. Fix the syntax errors (typos) and then test and debug the single function (or component of a program). Baby steps. Baby steps.

Step 7: Iterate and improve. Just keep adding things to your program to get it to where you want. Add a new feature. Improve an old one. Rip out some system and replace it. Add graphics. Upgrade them. Try to keep each of these changes as small as possible and test after each change. The longer it has been since it ran, the harder it will be to make it run.

_

I can not emphasize how important baby steps are. They are the key to avoiding fatal frustration. I have a law that helps define the size of subtasks: DO NOT EVER LEAVE THE COMPUTER IF YOUR PROGRAM DOES NOT RUN. You can take a piss or stretch. That’s it. I lived by this rule my entire programming career. You can’t always follow it, but try. Get your ass back in that chair. Mom wants you for dinner. Shrug. Your co-workers call you for a meeting. Snarl. I always think of a program like a car engine. You can sometimes merely tune it up, but a lot of times you have to take apart the engine to fix/add something new. That time when the engine is apart (the program does not RUN!) is very important, and should not be very long. If it is, you are not subdividing your tasks enough. I write all sorts of custom code to allow the engine to run again (even if in a half-assed way) while big changes are going on. These intermediate constructs are intended as throw-aways. But they save time. Having your program broken, writing more than a couple hours of new code that has not been tested, is a recipe for disaster. You could easily reach the point where you have no idea where the problem is. If you test in small bits as you go debugging is MUCH easier. Bugs are perhaps 80% likely in the most recently stuff. It’s the smoking gun you goto (haha) first.

You can do a lot with ASCII graphics!

A starter example of this whole process: My first game was a text based D&D type RPG game. I wanted to include a number of “cool” (to a 10 year-old) encounters. So I structured it as follows: There was the “character.” This was to be just a number of global variables (this is long before object oriented programming) like G (gold), HP (hitpoints) etc. I wrote a couple “methods” (functions – but they didn’t have names in BASIC, just line numbers) like “takes a hit.” This subtracts from HP, and if <= 0 branches to the “you are dead” part of the code (not really a function in those days). Then I wrote a number of “encounters.” These were the main flow of control in that program. It popped from encounter to encounter. They might be like: You have met an orc. draw orc on screen with text graphics (aka print statements). present options: “attack,” “run,” “use magic,” etc. wait for input and apply logic. If you are still alive send the player back to the main navigation loop (the place that doesn’t have a particular encounter).

That’s it. I expanded the program by doing things like: Adding more encounters. Adding resurrection as a pay option when you died. Adding an actual map to the main loop. Moving the “combat” logic from individual encounters into a function. Then adding to the character attributes like strength and dexterity which influenced combat. Beefing up character creation. Etc etc. These are all tasks that can individually be accomplished in a few hours. This is key. It keeps your program running most of the time. It provides good feedback on what you are doing.

The entire above “goal” -> “debug” loop can be repeated endlessly. Example: “add a save game.” You now have to save and restore the state of your player (various global variables). But to where? Disk presumably in those days. So you crack the BASIC manual and read about file I/O. First you go simple. There is one save game. It’s always named “adv.sav”. You write a function to open the file and write the vars into it. You examine the file to make sure it put them there the way you want to. You write another function to read the file. You add options to the game menu to call these functions. Then test.

Next baby step. Allow multiple save games. You add “filename” (or save slot or whatever) to the load/save functions. You hardwire it to something and test again. Then you add interface to the game’s main menu to specify which slot. You test that.

Iteration is king! Good luck.

_

Parts of this series are: [WhyThe SpecsGetting Started, School, Method]

Subscribe to the blog (on the right), or follow me at:

Andy:  or blog

Or more posts on video gaming here.

And what I’m up to now here.

So you want to be a video game programmer? – part 3 – Getting Started

…CONTINUED from PART 2. Or start at Part 1.

Some kid is always asking me, “I love video games, how do I learn to program them?”

First of all, a warning. Reaching the skill level to be a professional video games programmer takes years. There are no shortcuts. You can not possibly go from nothing to professional grade skills in less than perhaps 2-3 years — and for that you’d have to be an uber-genius — usually it takes 5-10.

The good news is that you can start very young (8-10 — I started at 10) and you can do it on your own with common equipment and readily available information.

There are two basic approaches: home training and school. And while I personally recommend both, I’m going to use this post to give my own “origin story.” In followups we can apply these lessons to the present (programming itself hasn’t changed all that much in 30 years — there are just more libraries).

[ BTW, if you’re new to the blog and wondering who the hell I am in this context, click ]

Rewind to 1979. Some of my favorite things in the world were Dungeons and Dragons and arcade games. I was really too young to actually play D&D accurately, but I loved reading the books and modules (besides my regular diet of fantasy novels). I went to the Apple Store (not actually owned by Apple or nearly as glamourous as they are today — in fact, the owner resembled Gandalf) and saw the game Akalabeth running on an Apple II (not a + or an e, but an old school II). Boy did that set me to dreaming!

Then in 1980 my science teacher brought into class a Heathkit H8 her husband built (yes built). This early computer ran a lousy version of BASIC and possesed the world’s worst storage device: the audio tape drive. Actually punch cards were worse, but with the tape drive, saving your program bordered on impossible (at least for the sharing audio tapes with the rest of the class) and so you had to type it in repeatedly. We were given a single mimeographed sheet of paper with the BASIC commands. I read this a couple times and then wrote out longhand the first draft of a text-based RPG where you wandered around and fought orcs and trolls for gold and tretchure (this is how I spelled treasure at 10). During lunch I typed in and debugged the game, editing my paper copy as needed. I used my friends as beta-testers. It may seem overly ambitious to try and recreate D&D as one’s first program, but it illustrates the programmer principle of: program what you love.

Then my best friend got himself a brand new Apple II+ (just released). This was a slick update of the Apple II. It had a whole 48k, came with BASIC, and was often (but not always) accompanied by a 143k floppy disk drive! Low low price of $900 just for the floppy drive! In any case, the II+ was so much more awesome than the Heathkit. It even had graphics!

So I began pestering my father for an Apple. This took 9-10 months of continuous harassment — the machine was expensive — and all sorts of creative techniques to convince him. I offered to mow the lawn for free. I explained how various accounting software would make balancing his checkbook a breeze, etc. Once I was victorious (Jan 1981) we got the accounting software, but he never used it, leaving me to my own devices on the machine. And I think I kept getting paid for the lawn. Still, this episode illustrates another important programmer principle: persistence.

After the Apple arrived, I spent nearly all of my free time (perhaps 6-8 hours a day) on the thing for years. This is essential. You must offer up blood onto the alter of the programming gods. Principle: sacrifice. I used this time in many ways. I played a lot of games. I used every piece of software. I taught myself to program. I hacked. Principle: market research. But I couldn’t afford as many games as I wanted and in those early years the available library was small, so I was always trying to make my own.

I wrote totally lame versions of nearly every arcade game ever made. In BASIC at first (we’ll get to the issue of environment later). I would generally spend a day or three banging these out until they were marginally playable and then move on to new projects. Lesson here: practice. I chose more and more ambitious games and would use each one to teach me something new. I did this in incremental steps, mostly 1-2 day projects. By way of example, I might upgrade something or I might add a load/save system (requiring learning about I/O). My early games didn’t have much in the way of collision, later ones did. I started with text, then moved up to lores graphics, then highres, then shape tables, then bits of assembly language subroutines for blitting. Principle here: baby steps.

Baby steps are incredibly important. You can’t learn everything there is to know in computers in one shot. Each little area takes multiple projects and days — at least — to learn and master. Take file I/O. I’m sure I got something up and going the first day or two back in the early 80s when I decided to add a load/save system, but I was still learning about file I/O 25 years later on Jak 3 (of course then I was inventing new ways of doing stream I/O, but it was learning nonetheless). Your first pass might work, but often you barely understand any of the principles involved.

You have to start simple, build up blocks, and go from there. That’s why interpreted languages and text programs are a good way to begin. You need to learn about variables, scope, and flow of control before you can jump into 3D graphics. And forget about complex unforgiving environments like C/C++ or assembly to begin with. Those come later and are just one more thing to spend a series of baby steps on. Just learning about makefiles or projects and compile options could stop a novice dead. So don’t — yet. Each task (and thing to learn) should be broken into some chunk that only takes a couple days at most to digest — or at least make some headway on. This leads to a virtuous feedback loop of progress and learning.

I kept writing those lame little games for about 3 years (100s of them). Of all my friends with computers (we all programmed in that era because computers didn’t do much if you didn’t program) my games were the coolest. I used them to invent all sorts of excuses to develop new skills. I wanted to learn about interpreters so I made an engine to allow the creation of text adventure games using a custom scripting language. Once I got this going I upgraded it to graphic adventures, which proved to be a perfect excuse to implement an idea I had seen in the Sierra games where line drawing and fill commands were used to compress images to a fraction of their raw size. On the Apple II a raw graphics screen was 8k. So a floppy only fit 17. A normal compressor (ancestor of zip) might squeeze this to 3-4k but that is still only 30-35 images. This “save the drawing commands” style made them a fraction of that. But for it to work I not only had to create the “renderer” (including an assembly fill routine) but I also a whole “paint program” to allow the recording/creation of these proprietary images.

However, each of these sub-steps resulted in satisfying progress on its own. Principle: chunking. For example that fill routine. It took several days, and my mastery of recursion in assembly wasn’t the best so it left little corners unfilled, but it was cool in of itself. My first fill routine (in BASIC) took 5 minutes to do a fill, and the assembly one only a second or two. Plus, I was to keep using it in all sorts of programs for years (with improvements). Principle: reuse. Building on the tools you make is essential to programming.

In 1982, I met Jason Rubin. He also programmed. He was an amazing (by the standards of the time and our age) artist and his games LOOKED REALLY COOL. But they crashed a lot. Mine rarely did. From the beginning I hated crashing. Still can’t tolerate it. I have trouble leaving the keyboard if a crash bug is still outstanding. Principle: perfectionism. My programs also did much cooler “programming” stuff. They just didn’t look cool. When we combined our talents, things really took off! Our games now looked cool AND ran decently. Impressive stuff. Lesson: partnership. Not everyone can be good at every aspect of computers. Nor even of programming itself.

CONTINUED with Part 4 – School!

_

Parts of this series are: [WhyThe Specs, Getting Started, School, Method]

Subscribe to the blog (on the right), or follow me at:

Andy:  or blog

Or more posts on video gaming here.

And what I’m up to now here.