It was also enlightening.
For the past several years I’ve spent most of my development time with C++11 in Xcode. I like it. Nah, I love it. But this weekend, working in Adobe Flash Professional with ActionScript 3.0, I could not believe how high my productivity was. I was knocking off tasks like they were popcorns in a fire. It helps that I used to work in Flash a lot, so I knew the drill. But I had forgotten how easy and quick it is to make games in that system.
The contest limit is 48 hours, but I actually spent 30 hours. In that time I made an entire game, and not a terribly simple one: it involves Box2D physics and time travel. It’s not a highly polished game, of course. I’m going to work on it some more before really “releasing” it (though you can play it now if you want). But it has all the main bells and whistles: front end, HUD, user interface, the game proper, victory screens—even music. Not that that’s anything special—the contest is to make a complete game, and over a thousand contestants did so.
Yet most of the games I make in my professional job take much longer than this. As I reached the end of the weekend I couldn’t help but ask myself, “How is it that you were able to complete this game in less than 48 hours, when most of the games you work on take upwards of several months?”
The last game I shipped, House of Shadows, took 11 months. Even if you assume that it was 10 times more complicated than Spacetime Adventure, this still leaves a productivity ratio of about 6:1. This means that if I could transfer the pace of production from Ludum Dare into my normal work, I would complete a game like House of Shadows in less than 2 months.
Now no doubt some of the differences between a Ludum Dare project and a “real” project are esoteric and non-transferable. House of Shadows, for example, is really probably more than ten times more complicated than Spacetime Adventure, thinking in terms of the internal game mechanics, rules, variation, and user interface. Spacetime Adventure gets away with being pretty simple really. But along with this kind of non-transferable difference, perhaps there are other differences that are transferable. Maybe there are things about creating a 48 hour project that can make a “real” project faster and maybe even more fun.
Intensity of focus. Almost all my waking hours were dedicated to programming during the 48 hours of the contest. I even took less sleep. This intensity of focus allowed me to maintain contact with the concepts and issues in the game so that I was able to remain productive without costly ramp-up and ramp-down times.
Expectation of constant closure. I expected to be done fast. At the macro level for the game as a whole. At the micro level for individual tasks. I was not at all happy with tasks, bugs, or setbacks that threatened the rigid deadline. I expected to make rapid, constant progress and I made sure I did.
Freedom from IDE distractions. One of the worst hits to productivity in my usual development setup—although fortunately this is not a daily problem—is when some aspect of the tools themselves go so slow that they lose my attention. If I have to Rebuild All, or work with a slow Photoshop, or if Xcode is hanging and crashing, not only does this cost time immediately, but it also causes me to get distracted. I try to fill the time by checking email or Hacker News, and this costs yet more time. During Ludum Dare, I remained tightly interfaced with Flash. I was continually in the midst of the edit -> compile -> test -> edit loop. This was one of the largest reasons for the high pace of production. The IDE did not kick me out at any time. It gave me no reason to look away. I need that in my daily work.
Easy object placement and animation tools. The UI work in particular went incredibly fast and this was entirely due to working in Flash. I could drag a bitmap into Flash to import it, then place it, position it, add filters, animate it, and attach the animations to code all in one tight motion, all within Flash. Tasks that can take a whole day took minutes. I need this all the time.
Lower degree of polish. Spacetime Adventure is reasonably complete but it’s not a final, shippable, polished game. Part of the slowness of a normal, professional game project is the degree of polish that goes into the product. As a rough estimate, I’d say that polish approximately doubles the length of a project. If I had to add features like sound effects, particles, more UI animations, button states, higher-quality art, variety of art, and additional gameplay features to Spacetime Adventure, it would have taken at least twice as long.
No responsibility for maintenance. Creating a maintainable game—one that is capable of long-term repair and expansion—is more difficult than a quick, throw-away game like Spacetime Adventure. In actual fact, Spacetime Adventure’s code is generally pretty clean and maintainable, but this quality happened to come easily, in part because of the smallness of the game; it wasn’t hard-won. And there is “slop” in the code that I would not have been comfortable with if I expected to have to live with the game for longer or expand it much larger. When you can write sloppy, get-it-done code, it pays to do so. When you can’t, it doesn’t. With Ludum Dare you always can. With production code, you rarely can.
C++ headers. More than once during the competition I would reach a point in the code and think, “Argh, I don’t want to have to add/change/look up/remove that function because it would mean having to mess with the header file.” Then I thought, “Oh wait, this isn’t C++. There are no header files.” The feeling of liberation and simplicity that hit me in those moments convinced me that for a great deal of coding situations, headers are a serious bane. They impart a constant agony of redundancy onto everthing you write. Every substantial (i.e. semantic) change must touch two files, and do so in a coordinated way. The simplicity and immediacy of single-file ActionScript classes felt like a breath of fresh air.
There is a place for the header/source division. For established code, dividing classes makes for faster compilation for both the user and the provider. This is rarely an issue in “game programming” proper (as opposed to “engine programming”).
This point, along with a few others in this list, convinces me once and for all that scripting languages are the way to go for most game programming. When these aren’t available, my friend Wouter van Oortmerssen’s Java Style Classes in C++ may provide a handy workaround. I’m thinking of trying it for my current project’s game code.
Performance and safety obliviousness. I know this is an old lesson that needs no explication, but I was struck more forcefully than ever how C++ imposes a significant mental cost on programmers to use the language carefully. This sounds like more of a bash against C++ than it really is. You use C++ precisely when you need high performance. The reason I normally program games in C++ instead of in Flash is that my performance testing of ActionScript reveals that it is at least an order of magnitude too slow for the kind of games I make on the kinds of platforms I normally make them for. I like C++ because it gives me many of the benefits of ActionScript (and other high level languages) while enabling lightning speed performance.
But this weekend I felt more than ever the liberation that comes when you don’t have to dance the C++ dance. When deleting something I simply set the reference to null. I can do the same thing in C++ by using std::shared_ptr, but even then one still has to be mindful of cycles. The word “mindful” here is not as innocent as it sounds. The detection and anticipation of object graph cycles while in the middle of coding is non-trivial. A programmer’s chief resource is the energy of his or her mind. Everything that expends or depletes that energy makes him or her less effective, more tired, and less happy. There were several moments during the competition when I thought, “I need to delete this expensive resource. I’ll set it to null. Ah, but are there any cycles that might keep it afloat?” And then I remembered, “Yes, but the whole cycle will die along with it.” There was a palpable feeling of relief when I realized that I didn’t need to worry about the cycles. I could use that mental energy to focus on the game itself.
It’s not just memory management. The whole context of Flash/ActionScript made me less concerned about performance. I know Flash is slow. At the beginning of the project I did some testing and confirmed that it was fast enough. From that point on I never worried about performance again.
It’s remarkable how subtle and constant the performance concern is. A good C++ programmer—especially one working on a relatively slow platform like mobile phones—is continually assessing the cost of what he or she is writing. Should I use a vector here? A map? An unordered_map? Will it be faster to pass this argument by reference? Should I reserve() this vector so that it doesn’t overshoot its necessary size? You use C++ because you want to squeeze frame rate out of tightly constrained hardware. Every variable, every function becomes a potential choke point, and a seasoned programmer is always measuring the ramifications of each choice. The C++ programmer is a deer sniffing the air for the scent of boots and gunpowder: everything’s an opportunity for gain; everything’s an opportunity for calamity.
When performance is of the essence, this state of alertness is an appropriate price to pay. But when you don’t have to pay that price—and in every game there are systems that have no serious likelihood of bottlenecking—you will gain mental energy back by essentially ignoring performance. You cannot do this in C++: it requires an awareness of execution and memory costs at every step. This is another argument in favor of never building a game without a good scripting language for the highest-level code. In ActionScript I fell into an easy rhythm of doing what I needed to do for the game behavior. I did not worry about the cost of an Array vs. a Vector: I used what was convenient. I felt a little lazy being so carefree. But the approach cost me nothing: the game runs like butter even on older desktop systems.
Minimal Snowballing. In the broadest sense, a 48 hour project minimizes a problem that plagues all projects. Work tends to snowball. For every task there are “task addendums” that extend the total effort. It’s not enough just to put an asteroid into the game. Beforehand you have to design the asteroid, talk about the asteroid, schedule the asteroid. Once the asteroid is written you have to test the asteroid, commit the code, adjust the asteroid, review the code, adjust it some more, document it, adjust the comments, fix the commit, refactor, optimize, extend. This sounds like the standard complaint about project management: projects should be simple but management adds cruft. Yet in some sense any project—even one undertaken by a single person—is susceptible to snowballing. It’s an odd thing, hard to put your finger on. Every task begets more tasks at the code level (typing, commenting, optimization) and the quality level (testing, debugging, refining).
It’s almost mathematical. For every hour you spend working, you must spend another 10 minutes responding to or expanding that work. After six hours of working you have accumulated an additional 1 hour of this metawork, which of course—being work—needs its own 10 minutes of response and expansion. Six hours of metawork later, you’ve accumulated an hour of metametawork, which needs yet another layer of response and expansion, and so on. Each layer of metawork is another layer of snow on the snowball. The larger the tasks get, the larger the tasks get.
In a 48 hour project this cycle is defeated—or at least minimized—by the sheer concentration of focus. There are no “metatasks”—there are only tasks. You don’t have to re-learn what you did yesterday, because there was no yesterday. You don’t have to plan for next week. You don’t have time to talk about what you’re doing—you think fast, then you act. This can’t be the best way to accomplish just any project, but when it’s possible it is incredibly efficient, and that efficiency is incredibly satisfying.
Many of these lessons are ones I’ve learned before. Many are classic “agile” dogma. But Ludum Dare put me in direct contact with ways in which my own practices and tools fell beneath the ideal.
For my own purposes, the actions are:
- Investigate a game development solution that combines the high-performance of C++ on mobile with the tools and script support of Flash. Unity looks promising. Building a SWF importer for my engine could work. Adding script support to my engine and greatly refining my tools would go some of the distance. Gotta do something.
- Try out Wouter’s dual-pass C++ class solution for game objects.
- When my IDE slows me down, freaking beat that thing into shape right then. Do not read Hacker News.
- Look for opportunities to be sloppy and hacky. Does this code really need to be maintainable? Do this code really need to be efficient? Does this feature really need more polish?
- Changing my work schedule to a pattern of high-intensity days and calming days could be interesting: Monday-Tuesday is a 48-hour project in microcosm; Wednesday is relatively calm; Thursday-Friday is another intense 48-hour project. Then the weekend. Would this burn me out or make me super fast and happy?