I'm taking a little detour from design analysis to share some insight on design, programming and project planning of our game jam project from last weekend. It's mostly going to be programming though, and mostly don'ts - we didn't finish the project in time. We got quite close though, so I'll come back to the design once some final bugs have been squashed and some levels have been created for the game.
I'll try to add some pictures soonish...
I've game jammed successfully twice this year. Both games were in fact quite good. They were also very well scoped down, and thus finished. This time around, I decided to take more risks with the scoping, and also do stuff I've totally not done before. This project definitely ramped the challenge up from the last two as evidenced by the fact that we were unable to finish in time with three full-time programmers and one apprentice. We had three main tasks: gameplay engine (it was a platformer with some twists), graphical effects and sound system. None of these were trivial, and no one in our team had really done anything of the stuff they were going to work on. I was in charge of the gameplay engine since we were developing with a library that I was the most familiar with.
Nevertheless, I think the scoping was realistic. In fact, I think our effective working time per person was less than 20 hours - clearly less than what I've had in previous game jams. Ultimately, we were not very far from first playable level. We had some minor bugs, some of them ignorable with level design. What we really lacked was levels. Kind of hard to show any gameplay with them. However, looking at the list of what we actually did build, it's fair to say we did really well. Here are some highlights: isometric platformer with climbing instead of jumping, sound system complete with radio channels and static between them, knobs for tuning frequencies and level elements affected by these frequencies, and finally, enough high quality art for a few levels.
On with the lessons...
3. Lesson: even when used as constants, magic numbers are still really bad
This one was my biggest personal failing, since I can't really blame any of the tools on this one. 2D-programming is often riddled with all sorts of offsets, margins and whatnot, because of the way sprites are handled. This is especially true for isometric 2D as sprites can hide behind each other, and characters are not standing on top of floor sprites but in the middle instead. All sorts of constants. The mistake I made was basically that I did not have any system, I just made estimations for each value using Stetson-Harrison, and at some point the entire system just crashed down on me hard. So hard in fact that I was only able to recover the situation on Sunday morning after a night's sleep. In the end, I did it right in about two hours and now the system makes a lot more sense. I also actually measured all the offsets from the sprites (this would have been impossible earlier though, since the sprites were not finished and we hadn't really agreed on any specific measurements).
4. Lesson: isometric graphics in a platformer = way more trouble than it's worth
When we started out I was thinking about simple side-view 2D. However I didn't communicate this clearly enough, and our artist started with isometric graphics, and me, not realizing what a pain that would end up becoming, okayed it since it did look pretty damn good. What a big big mistake. See, one of the biggest problems is that while in side-view 2D collision detection is easy, with isometric it is not because the sprite size is not equal to the space it takes in the game's internal logic. To further complicate the issue, the library we were using did not support custom hitboxes for collision detection for both parties. Since none of our sprites were equals of their hitboxes, there was trouble. Unfortunately even more so, because I tried to figure my way out of this mess with offsets and margins.
Another problem with isometry is the z-order of sprites. For example, when on the left side of an obstacle, the player sprite has to be behind it, but when on the right side, it needs to be in front. This got even trickier when we chose to use climbing instead of jumping (a sound decision, jumping in a horror game does look a little silly). During climbing from the left side, part of the player sprite needs to be in front of the obstacle (the top half, which is above the obstacle) while the rest is behind. This was solved by splitting the player sprite in two parts during climbing, and was not that hard in the end. Another consequence of climbing is that the sprite can only climb a given fixed height without making the animation look stupid. This is just a level design issue though, and indeed most platformers have their level elements placed on square grids anyway.
Later on I also realized that this is going to come back to haunt us with our ghost enemies, because they can move through everything in the game. It's going to be pretty damn painful to figure out a system where they can at the same time be in front and behind objects...
5. Lesson: plan for earlier integration
Three programmers working separately is okay, especially with version control. However, I would advise planning for integration at milestones, not just the end. It's really crushing to motivation sometimes to only see your part of the game nearing completion, and never getting a glimpse of the end result until, well, the end. We did this mistake in the last game jam where we literally had no idea if the game idea would ever work before it was about one hour away from complete. Fortunately it did work... This time around, since we had no time to make any actual gameplay, I'm still not sure if this idea actually works. So yeah, the old wisdom of prototyping early should be followed in game jams as well.
I guess that covers it for now. As promised, I'll get back to design after I have had the chance to make some gameplay. The game will be released online and be playable without any special plugins, so you can hopefully see the end result for yourselves as well.