Chicago Game Jam 2013 Post Mortem
(Grave Danger by HDCheese)
Grave DangerThe Team
Team HDCheese is:
Mike Turano (programming
Brandon Sharas (art)
We had music assistance from the talented Marcus Bailey.
The Setup
We participated in the Chicago Game Jam 2013 at The Nerdery October 25 – 27. It is listed as a 48 hour
game jam, but was in reality more like 30-something hours. The theme was announced Friday night,
teams formed, and then everyone went home and came back out around 8 AM the next day to work
right through to the deadline the next morning. We came with our 2-man team already formed: a
programmer/artist team where I was doing the programming and Brandon was doing the art. I used
the excellent libGDX (a cross-platform Java framework somewhat similar to XNA in scope) to build
our game, with some small amount of my own code to handle game state management, some display
conveniences (animation management, aspect ratio correction for game world drawing, etc), and a few
math functions. I wasn’t doing it from scratch, per se, but I was definitely missing out on a lot of basics
that would have been provided for me by an engine like Unity, Gamemaker, GameSalad (who was a
sponsor, yay!), or even a more mature personal engine.
The theme was announced: “Death.”
The Design
It surprised us how broad the theme was, but it was going to allow us a lot of freedom in our design.
Immediately after the theme was announced Friday night we started spit-balling ideas. We pretty
quickly settled on one – we would make a local co-op game with a small level where the players were
grave robbers in service of a mad doctor who needed “parts” for… whatever evil things he does. The
players need to rob graves in order to fulfill a quota of “parts” in order to proceed to the next level.
There would be graves that needed to be “dug out,” which would take a certain amount of time, as
meanwhile the players were being hounded by enemies. Upon opening a grave, there would be a
chance that either helpful body parts would spawn for collection or a vicious enemy would spawn to
attack the player. Combat would be difficult, to discourage brawling and encourage running, hiding,
and teamwork distraction of enemies. We also wanted to somehow implement a betrayal mechanic
– all players and enemies would drop parts when they died, so if your teammate died – either by an
enemy’s hand or yours – you could then collect his parts and they would add to your total. Levels would
be small, and the map would be tile-based, but allow dynamic entities (players, monsters) to move in
between tiles and handle collision with axis aligned rectangle collision with other dynamic entities. The
maps would be randomly generated, but there would be no rooms and few objects that were barriers
to movement in order to keep the generation process simple. We also wanted there to be “items” that
players could only use one at a time, which would either make you better at fighting or better at digging,
in order to encourage sort of a player class mechanic. Body parts would have to be carried back to a
cart at the end of the level (taking up your item slot) in order to be counted towards your total.
We came up with a title right away – “Grave Danger.” We loved the design – this game was going to be
awesome, the scope was reasonable and it would be super fun!
There was a lot of emphasis on mile stones during the opening presentation at the game jam, and we
wisely took it to heart. We created some mile stones for our game, and as a broad estimate I basically
rated each milestone as “difficult” or “simple” in terms of required time investment. Here are our
milestones, roughly in order:
1. Collision and Movement (difficult)
2. Animated Sprites (simple)
3. Multiplayer (simple)
4. Automatic Level Generation (difficult)
5. Enemies (difficult)
6. Combat (difficult)
7. Items (difficult)
8. Win/Loss Conditions (simple)
As a basic estimate, I was assuming any “difficult” task to take 6 hours, and any “simple” task to take 2
hours. It looked like we had our work cut out for ourselves, as by the time we had settled on this list of
milestones, we had less time than the indicated total – not allowing any time for sleep between Friday
night and Sunday morning. I was banking on having over-estimated, though, so we went to sleep Friday
night confident of our ability to pull it off.
The Reality
We woke up early the next morning and arrived at the venue – The Nerdery in Chicago (http://
nerdery.com/) – who generously allowed us to use a portion of their well-equipped space that included
a projector, a common area with several tables, and several rooms with white boards that teams could
shut themselves in to work / take a nap in.
We arrived not long after the venue opened in order to claim a good spot at a table. We didn’t
oversleep and seemed to be one of the first few groups there. We picked up some McDonald’s
breakfast on the way over. So far, so good.
Brandon chose a very distinctive style for all the artwork that would be mostly 90 degree angles, with
occasional use of 45 (or so) degree angles. He mocked up some characters and we were both excited
about the art direction. He started pumping out characters and their associated animations. It would
be a top down game, so he would need to animate everything from 4 directions (my simple animation
system had only handled side view before, so in order to keep things simpler for me he was willing to
flip the animations himself and I could just treat them as separate assets). We didn’t see this huge
undertaking as too much of a problem for him, as we knew I would be the real bottleneck for time
anyway.
One of the sound guys there, Marcus Bailey, was offering to make music for teams besides his own.
Brandon talked to him about the game’s vibe to try to get the music straight. A little while later Marcus
came up with a creepy but catchy little tune for the game and our music was covered.
I began to work on collision and movement. As a test run in the week leading up the jam, I had coded a
simple tile-based map collision system with dynamic entities that had discrete movement from scratch
as practice. I could pull this off in about 5 hours over 2 practice sessions at home. I started on the
movement first. I was using integers to represent the velocity and map positions, but breaking out any
fractional portions into vectors and floats in order to allow acceleration and deceleration based on time
rather than simply setting the speed every frame. This was a mistake, as I was somehow getting this
wrong, even though in my practice session it had been working fine. The movement took too long.
Then I got into making the controllers work. Handling 2 axes of movement input in a top down game
with a controller was a bit weirder than I had anticipated, and I hadn’t actually practiced with the
controllers – my only experience using controllers in libGDX had involved a single axis of movement…
diagonal overhead movement and it’s interplay with the controller-sent input became a major disaster.
A few hours went by before I hacked in something less interesting but more predictable than the weird
behavior I was initially getting. I wasn’t handling diagonal movement properly at all, but if the player
stuck to the 4 cardinal directions only it worked. I was behind, and I hated the way my movement felt,
but I tried to move on.
Then it was on to collision. I thought I knew what I was doing here, also, but right off the bat I started
noticing some wonky behavior that I hadn’t seen during practice. Things weren’t being displaced out of
“barrier” map tiles correctly, my calculations seems to be weirdly off, it was impossible for the player
to pass between a 1 tile gap, and when I undersized his collision boundary too much my formula didn’t
work anymore. If I undersized the characters just a bit it could work better, but required an unfair
amount of precision from the player. My mental state really started to deteriorate. My movement
sucked and my collision sucked, and I was spending way too much time on it. We broke to eat at some
point, and the short walk and break to eat some fast food helped me realize one of the mistakes I
had been making – having to do with the fixed time step I had sloppily implemented. That realization
did help, but it didn’t fix the most glaring issues with my broken system. I had to toss in some magic
numbers before I finally got it to “mostly work. “
I was really depressed and angry at this point. My most basic systems were already bug riddled, and
they had taken way too long to get to a just-barely-working state. I was getting ready to move on to
something else, but then I took one more shot at the movement velocity– ripping out all the integers
and just changing them to floats, and hacking apart anything that got in the way. It worked to make the
movement a lot better than it was. Collision was still screwed up, and the controls still didn’t handle
diagonals properly, but the movement was much better than it had been.
Next, I put the character graphics and animation for the player in. Brandon had wisely created
placeholder graphics early on, but we were already so far along on time and he had already made so
many “final” assets that I just put in the final version of the player graphics. We noticed that the scale
was off – his great artwork was getting scaled down badly and suffered a bit for it. It was too late,
though, so he just kept the same scale as he kept working. “Just get it to work” became our mantra.
I moved on to combat next. I made a simple attack that would have the attacker create a hit box in the
direction he had most recently been moving in that could strike any entities (including players), and
introduce a “stun” to himself that would prevent him from accepting any commands again for a time.
Attacks would also “stun” an opposing entity hit by them. It worked about how I had expected and
there weren’t any surprises there fortunately.
At this point we had about 10 hours left for everything else. We re-examined our milestones and
decided to cut out the concept of items entirely, and remove the concept of win/loss and parts
“carrying” entirely – your “parts” would just become your score and you would try to get the highest
score you could.
I got “digging” working next by simply having the player attack the graves in order to chip away at their
“health” before transforming them to “open graves.” No surprises there.
I moved on to enemies next. I got a “night watchman” enemy occasionally spawning randomly in the
level. He had two states: wander and chase. I wasn’t going to get fancy with the AI, just have him do
really dumb chase where he looks for the closest player and then chooses to walk towards him along
the longest axis, or for wander he will randomly choose a direction. I made them attack whenever the
player was very close to them, and because I had already made the attack dependent on the walking
direction, and the enemies would always walk towards the player, the attack basically magically worked
for the enemies. When they bumped into map objects they would enter the wander state for a time.
Overall the enemies ended up behaving better than expected and were completed fairly quickly.
We threw out random generation entirely and I asked Brandon to draw out a level on graph paper we
had brought and I would just hard-code the map values using what he came up with.
There were probably about 4 hours left at this point. With enemies actually chasing the player now
(and viciously murdering him) as he tried to run around and dig up graves, it was starting to feel more
like a game. Brandon had been begun working on all the sound effects, finding objects to use and
using his voice to record sounds for attacks, hurt sounds, etc. I put in the “parts” next. When a grave
was opened, or an enemy died, or a player died, 10 parts would randomly spawn, some of which were
uncollectable “bones” that didn’t add to your parts total. It all worked.
We finally started playing multiplayer for the first time. I hacked in some camera zooming to attempt to
address players leaving the same screen area. It was far from perfect and consisted entirely of guessed
magic numbers, but it kind of worked. “Just make it work.”
We had about 2 hours left. We had never added the enemy that could spawn when you dig up a grave,
and I didn’t feel we had time to do it. We left out the skeleton enemy Brandon had already created all
the animations for because I didn’t think I could fit it in time. I finally put in sound effects that Brandon
had recorded, and the music Marcus had made. This was all straight forward. My simple sound library
was configured to accept multiple sound files as the definition of a single type of sound and randomly
select between them automatically, so I was able to use all the various sounds that Brandon recorded
to add a bit of variety to the sounds without any real time investment on my part. We did some last
minute tuning, I inserted Brandon’s title screen and loading screen images. It was stretching them. Oh
well, just make it work.
I did some minor tuning to movement values at the last minute, I think I screwed it up a bit as
movement ended up “slidier” than I had intended, but time was basically up. We also never really
built in a compelling reason to betray your teammate, as doing so would only cause the enemies to
concentrate on you instead. You could still collect their parts, though.
Despite everything, we had finished! It was a fully functional, if buggy, game! Multiplayer was actually
kind of fun, and the art and music really made it pop.
What Worked
The milestones were crucial. Being able to look at our milestones regularly and determine what was
truly necessary for a complete game that accomplished as many of our design goals as possible and
was still possible to create in the remaining time is the only thing that allowed us to finish despite my
programming disaster. Here’s how our milestones ended up shaking out:
1. Collision and Movement (difficult) <– broken but “works”
2. Animated Sprites (simple) <– inefficient asset creation but works
3. Multiplayer (simple) <– works, but no usability polish
4. Automatic Level Generation (difficult) <– cancelled due to time
5. Enemies (difficult) <– works
6. Combat (difficult) <– works
7. Items (difficult) <– cancelled due to time
8. Win/Loss Conditions (simple) <– cancelled in favor of simple “score only” setup
The scope was realistic. We did a good job of not going too far overboard with our scoping. Even
though the “items” idea turned out to be a bit much, we still had a complete game without it, so that
proves the concept was not fundamentally too large.
We had done 1 game jam prior to this (our first), and we were woefully ignorant of how to scope
appropriately, or how to plan our time. It was a miracle we got something working by the end of that
one, and it was only because of wide swaths of feature slashing that ended up creating a game utterly
different than what we had planned and envisioned.
What Didn’t Work
I didn’t stick to the milestone order as strictly as I should have. Mainly, I should have started putting
Brandon’s placeholder graphics in earlier so that he could have adjusted the size of the assets he was
creating to be more appropriate to the zoom level we were working with for the game. More generally,
this issue with the art pointed out that our workflow could use some additional tooling or at a minimum
just earlier and more in-depth coordination before all the parameters for generated art are settled
upon.
I was not truly accounting for the fact that code created under pressure is not as good as code created
at home with no time pressure. I am not a brilliant savant programmer. If I had just taken the simple
way out with movement earlier (not bothering to break out integers and just using floats for everything
instead) I could have saved a lot of time and frustration. As far as collision is concerned, I probably
should have just gone with pure axis aligned rectangle collisions with inefficient checking instead of
even using tiles. What I will more likely do for next time is to have created my own general purpose 2D
collision system that is gameplay agnostic that I will make part of my “kit,” intended for use with all 2D
games I make going forward.
The other option would be to learn a tool like GameMaker, GameSalad, etc, but I like to use game jams
as an opportunity to beef up my general purpose tools anyway, so for me that option is not a good one.
I would highly recommend using these tools for anyone interested, though!