gw0rp Postmortem

Stephen Johnson — Apr 13, 2009

The Creative Itch Begins

It was the spring of 2008, and I hadn’t finished anything in a year. I was still easing into college, so I was very busy, but I missed game development. Even though iDevGames hadn’t run a contest in some time, I decided to create a game design to put on file just to satisfy my creative itch. I thought about games during my twenty minute walk to class one day and came up with the modular ship concept — I became very excited and drew a quick mockup:

Scribbling madly in what was once an Arabic-language weekly planner, I showed my idea to some friends, one of whom was Calvin Eiber. Calvin helped me think up new kinds of ship parts and how they might interact with an environment. The PyWeek contest started a few weeks later, and I tried to make a prototype with a homemade physics engine, but failed and scrapped the whole project without ever releasing a demo of any kind. Around July 2008, I wondered where Kid Pix had gone and started to work on a painting program called Splatterboard. It was a great vehicle for weird graphical ideas, like the Double Helix DNA paintbrush. I made a lot of progress on it, but when uDevGames hit, I had to drop it entirely… or did I? More on that later.

I chose to write gw0rp for uDevGames 2008 because I needed to — It was too good an idea to pass up. I had a few others, most of which were easier to execute, but gw0rp was a game that needed to be made, or at least prototyped. I started by writing up a basic design document that outlined a few basic unit types: the Brain, fixed and “guided” thrusters, fixed and guided turrets, “logic” and “power” units, a shield generator, and a repair unit. Guess how many of those made it into the game!

After I wrote the design document, I looked for a physics engine with Python bindings and found Chipmunk / pymunk. I ran a few tests and found that with tweaks, it would be suitable for my needs. Another week passed, and I had a demo with a room full of thrusters that you could attach and detach. While I was writing the demo, I gathered team members. Calvin was easy to bring in because of his earlier involvement, skill with SolidWorks, and level of excitement. I also found a guy who I’ll call False Start #1 who claimed to want to do level design. We took an evening to hash out a design. That’s when things started going wrong.

Design Continues

I came to the design meeting with my head full of physics puzzles and ship configurations. Calvin came to the meeting with his head full of plot twists. False Start #1 came to the meeting with his head full of sand. Instead of discussing ways to challenge the player, I spent most of the meeting trying to explain to the other guys that it is not possible to make Diablo II in three months. I left the meeting with a better idea of what I needed to do to support Calvin’s plot, but I had no idea how the levels were going to look. I was going to code, Calvin was going to make art, and False Start #1 was going to “design levels.”

My winter break was during the last two weeks of December. I spent almost all of it on the couch in my parents’ house with my laptop. I added features rapidly and restructured code when it grew cumbersome. I decided that a graphical level editor was an absolute necessity, so I ripped out most of Splatterboard’s guts and made it write to gw0rp’s level format. I decided to use Splatterboard’s code because it already had a working GUI with a somewhat stable plug-in system. During the break, I learned that False Start #1 had been kicked out of school. He told me that he still wanted to work on levels, but never actually produced anything or even checked the developer diary. I wrote him off and started looking for a new level designer.

By the end of winter break, False Start #2 had offered to be my level designer. He downloaded the editor himself and sent me a test level. It was confusing and didn’t work completely. He never sent me anything else. When I realized that I wouldn’t be able to find an outside level designer in time, I helped Calvin set up the editor in Windows Vista so that he could make levels himself to fit the story line he had written. Now we were a team of only two: me, the coder and packager, and Calvin, the Windows-using graphics/levels/story guy.

Rapid Progress

I wrote code. I added content. I discussed the story with Calvin. Those discussions often did not go very well. I had to keep pulling him back, because he kept trying to introduce features when I was trying to fix existing bugs that often came out of hastily-added new features. Most of February passed this way. During February, I was finally able to release the game to the public for some play testing. It did not go well. The controls were confusing, the level design was hostile, and there were various crash-inducing bugs. During the last two weeks of February, I tested aggressively, fixed crashes whenever I found them, and attempted to fix some of the broken level design. While Calvin’s levels looked very good, they were often confusing to play or caused problems with the physics engine. I’m pretty sure that the reason is that he never actually played the game — two-man team in which one man doesn’t actually check the results of his work. I thought it was justified, though; gw0rp uses a few Python libraries that need to be compiled separately for different platforms, and I didn’t know anything about getting them to run in Windows. The level editor, on the other hand, just uses Pyglet, which is pure Python. Calvin seemed to be doing just fine with GIMP and my level editor, so I never really thought about it until I watched someone else try to play the second mission. I fixed many of the problems before the deadline, but that second mission still represents everything that is wrong with the game.

The weekend before the deadline, I managed to get a Python interpreter packaged with the game so that it would run on older systems. I fixed a few remaining bugs and level design issues and called it done. A few days later, after voting had already begun, I decided that it wasn’t done after all and removed most of the second mission, since it had caused nothing but trouble since the start; I have never felt so good about getting rid of content.

This game is easily the biggest thing I have ever written. The SLOCcount utility puts the game code alone at 7500 lines. With the level editor, it’s 10,000 lines. Although the version of gw0rp that ended up in the contest isn’t the game I actually wanted to make, it is at least a very good prototype of the internals, and proves that the core gameplay concept is sound. If (when) I choose to remake gw0rp, I will be able to move more quickly and design a more robust code base.

What Went Right

Originality

If you’re tempted to write the game off as “Katamari Damacy: IN SPAAAACE!”, then please think again. If gw0rp is based on anything, it’s Tumiki Fighters by ABA Games, who also created Torus Trooper. Tumiki Fighters is a side-scroller in which all enemies are made of parts, and when they explode, you can catch some of those parts as they fall and attach them to your ship. These stolen parts would shoot back at oncoming enemies and act as a shield. Gw0rp takes this concept several steps farther. There are a variety of unit types, and the shape of the player’s ship can make a big difference to the playability of an area.

Great story and cut scenes

Few people get the complete story because the second level irritates them enough to make them stop playing, but the whole thing is very, very good. There are many questions which are asked, and most of the important ones are answered. In the end, the game forces the player to be evil (there was going to be a choice, but we ran out of time.) The cutscene format also works very well.

Eye & ear candy

I made a single kind of explosion during January and it has worked well for everything. Calvin used SolidWorks, a CAD program, to make realistic machines and buildings. He learned GIMP in about a day and put together all of his art bits to form a coherent world. The animations, particularly the doors, flow well.

David Weiner of Atomicon provided excellent, realistic sounds that bring the world together. He was responsive to requests for changes and supportive of the development effort. He has my eternal thanks for working on gw0rp for free. When I couldn’t get in touch with him or needed something quick, the sfxr program provided an easy way to get a variety of sounds. Most of them don’t sound very good on their own, but when layered together, they can be very entertaining. Since David was busy at the end of the contest, I wrote most of the music in Garageband. The tracks for missions one, three, and five are based on things I wrote last year and never finished — I am very happy with how they turned out.

Powerful extensibility

The level format is versatile and the level scripting system is powerful. It is possible to do almost anything with levels, provided there are existing game objects that support it.

It’s a game!

Many of the uDevGames 2008 entries cannot really be called games. Calvin and I really pushed ourselves to create a complete game, not just a tech demo or prototype. There were bugs in the contest version of gw0rp that could have been fixed by the deadline if I hadn’t been implementing new features or adding content from Calvin, but I don’t regret that at all. The most important thing is that our entry was a complete game. A flawed game, but a complete one.

What Went Wrong

The story gets lost

Much of the story is lost to most players, since some of it happens in the form of tiny messages at the bottom of the screen during gameplay, which players universally ignore during combat, and ignore half the time out of combat anyway.

Need for friendlier level design

Calvin has never played his own levels. He has only watched me do it. Most of the levels are fine, but not the second level, which in my opinion is the most important. Essential puzzle-solving elements are often hidden offscreen or obscured. We tried to fix the situation by adding text at the bottom of the screen, but as previously mentioned, that text is mostly ignored because it happens during the action and it is at the bottom of the screen. We also added big green arrows, but those arrows are often not very helpful.

The level design also causes many problems with the physics engines. A few big rooms have doors which lead to very small spaces, and players often get stuck in those small spaces because the game dumps them in their last location, which is often next to a wall. I fixed most of these situations by explicitly moving the player to a safe spot in the level script, but that solution is very kludgy.

Stability

Calvin used my level system in a way that I didn’t expect. Instead of using a tiled background with polygons on top, he made a series of huge images and drew invisible collision lines over them. When I started testing the game on older hardware, I found that their graphics cards were often unable to handle such large textures. The game was also using 400+ MB of RAM, which is totally unacceptable for a game as small as gw0rp. The reason for the heavy RAM usage was my resource loading system, which was designed to make rapid development of small games easy. It walks a list of folders and loads up all the content on launch, then puts pointers to those resources in its global namespace so I can access them with a single short expression. This system is terrible for gw0rp because of those huge images. I had to write a hard-coded workaround at the last minute that would only keep a few of those huge images in memory at a time.

Ship configurability is a hindrance, not a feature

The game that we made is really just a normal top-down arcade game in which you happen to be able to attach floating units to yourself, and when a thruster gets blown up, it’s really irritating. Calvin’s levels exploit the ship configurability feature only rarely. In December, I was hoping to create clever physics puzzles. In February, I was frantically writing fixes for physics problems caused by area crossing. The original design included AI-guided thrusters that would allow players to assign keys to generic motions like “move forward” or “rotate right.” When the player pressed the key, the thrusters would rotate into position and thrust. Another early idea was to assign keys automatically based on the angle and position of the thruster. At least one of those will definitely make it into a future version of gw0rp, but for this contest, I had to freeze most of the features at the end of January.

Comments from the Public

iDevGames sent me feedback for the game from the voters and the following are my responses and thoughts.

Concept and gameplay

People really like the concept. Some find the ship hard to control, but most people say that they got used to it after a level or two. People had trouble reading the text at the bottom of the screen. Also, the ability to rotate and release units at will was not obvious. Some players didn’t notice the “release” buttons next to the unit labels and thought that they had to release things in whatever order the game dictated.

I think it’s good that it takes a couple of levels to get used to the controls, as long as those levels are both engaging and easy to complete with little skill. We tried to use the text at the bottom of the screen for storytelling and hint-giving only, but I think that it should be largely removed except for a few key areas where there isn’t any combat but where it would help the plot or a puzzle. I am still trying to think of ways to make the pause screen more obvious and user-friendly.

Level design

Some gamers found the first level to be slow and boring. Others found it necessary and helpful. In general, people thought it needed an earlier hook, either in story or gameplay. The objectives were occasionally confusing, and people felt confined by the consistently small corridors they had to navigate, which also caused many problems with the physics engine. Getting stuck in a wall after crossing levels was a common problem. Level crossings in general were jarring in general, and many people requested that levels be more unified. Although Calvin designed all of the levels, I am partly responsible for the constant level crossings. I expected Calvin to use a small tiled texture as a level background and place decals on top of it. Instead, he sent me huge images that made up all static parts of the level. I need to either provide a way to place small images in a tiled grid to make up a larger image, or redesign all the levels to use small tiled backgrounds. Actually, I should probably do both.

Graphics

In general, people liked the graphics. Those who had played early prototypes mentioned that they liked my old coder art better because it was more stylized and unique. The thrusters were originally simple grey anti-aliased spheres with friendly blue arrows on them that indicated the direction of thrust, and units were various colors with big, obvious symbols on them. The current graphics are all very low-contrast and use a limited color palette. Calvin was able to provide lots of art, but he was reluctant to change graphics once they had been sent to me. I had to tweak a lot of them by hand to remove white borders and separate them into top- and bottom-layer pieces. Also, while this gw0rp’s world is full of a lot of stuff, none of that stuff is very unique. It’s just a representation of a fairly standard military installation. There is nothing that really grabs your eye.

Story

Like the levels, people thought that the story was slow to develop and needed an earlier hook. They thought that while the story was a good one and added to the game, there was just too much to read, and much of the story could and should be replaced with graphics. I really liked the cutscene format. We decided early on that we would use as few fancy graphics as possible to tell the story, so I tried to make the text cut scenes as stylish as possible. I think it worked well. The faces of the characters used to be much more flat, colorful, and stylized than the current set of faces, and a few people mentioned that the old ones were better, but they weren’t a full set. I opted to use Calvin’s set instead of my original set rather than create new variations on the flat digital face theme. In retrospect, I should probably have just made a couple more. They aren’t very hard to make. In the future, I would definitely like to have some Boston-style cut scenes with comic-like still graphics.

Audio

Most people didn’t comment on the audio. A few said that the music was great, and one person said it was on the annoying side. I think that the audio was mostly excellent, except for a few sounds. The machine gun sound isn’t very convincing and is a little bit annoying. Unfortunately, it’s one of the most-played sounds in the game. Other than that, I like the way it turned out.

Overall

Everyone seemed to like the concept and a few said that they wanted to see me continue to develop it. These are great things to hear. I may not get back to it for a few months, maybe over a year, but I do have plans to return to this game.

Looking to the Future

I still haven’t made the game that I think needs to be made. When I get back to gw0rp this summer, or perhaps the summer after that, I will start by removing all existing content and about half of the code. I made some fundamental mistakes early on when I wrote the class structure, and I need to spend some time thinking about the best way to structure the internals.

I was surprised at how fast the game runs, but most of that speed is due to Psyco, an optimizer for Python bytecode. If I remove the optimizer, I lose 100 FPS and the audio stops working. I suspect that part of the reason for the audio issues is that gw0rp is single-threaded. I need to separate it into two or three threads instead of one monolithic game loop.

There are many gameplay and level design issues. I covered those in the feedback section. Even though the game has many problems, I am satisfied. Before uDevGames 2008, I had never made a game with content. Now I have content coming out of my ears. I also have the start of a more generic 2D game engine. Even if I don’t win any prizes, I can still be proud of the work I have done.

  • Developer: Steve Johnson
  • Title: gw0rp
  • Genre: Arcade
  • Team size: 3
  • Development hardware: 17" Macbook Pro, 15" Macbook Pro, iPhone 3G, M-Audio Firewire 410 audio interface, Sony MDR 7506 , Yamaha P-60 electronic piano, headphones, AMD box with 64-bit Vista (Level design, graphics)
  • Critical software: SolidWorks, AudioFinder 4, GarageBand, MOTU Digital Performer 5, Randgrind, TextMate, Stone Create, Sfxr, Audacity, Adobe Illustrator
  • APIs/Libraries: pyglet, pymunk, yaml, lepton, and psyco libraries