I made a game in three days for the 34th iteration of a popular game jam called Ludum Dare. My entry is a two-button futuristic racing game called Tech Rider. Well, I say racing–really it’s a time attack game.
You can play the game here.
My involvement in this game jam kind of came out of nowhere. Less than a week to the event, I realized two things:
- It was happening next weekend.
- Nothing was stopping me from entering.
With these things in mind, I decided to enter. It was a bit late to find anyone to work with, so I decided to enter solo. Because of this, I was on the fence about whether to enter the Compo (48 hours) or Jam (72 hours). In the end I went with the latter, but I was sure to follow the rules so I could make that decision near the end of the Compo.
(the game, not the racer – a brief prejam postmortem)
On the Thursday before the event began–23 hours to its start–I decided it would be a good idea to do a warmup game. So I set myself a time limit of three hours, spent about 15 hours doing preliminary setup stuff, and made Fly Killer.
This turned out to be a very good idea, because it helped me work on the kinks in my workflow. I rediscovered quirks in Unity (except the new scene management, but that’ll come up later), relearned a bit of what works with git, and revisited the flow from Aseprite to Tiled to Tiled2Unity to Unity.
I managed to hit my playable target within the three allotted hours, which was a huge boost to morale right before the jam. During development, I switched from a more traditional design of “move swatter over fly and click to swat” to the simpler “move swatter into fly to swat.” Personally, I found the latter more engaging–and it was easier to implement without bugs.
That out of the way, it was on to the main event!
Three Days to Tech Rider
What Went Wrong
Circuitous Route to Design
I spent a large part of the jam’s first 24 hours implementing a mechanic where pressing left and right together would cause your ship to charge, then pressing left or right after charged would cause your ship to “smash” in that direction. This was meant to be an attack mechanic.
Initially, the game was supposed to be a purely vertical racer with some turns thrown in. The focus was combat: destroy other racers as you catch up to them. This seemed a bit silly on further inspection, that each racer would either die by your hand or never be seen.
The charge and attack stayed throughout further development, even as I changed the strafe movement to turn movement and made the tracks less vertical. Late in the jam, some time on Monday, I realized that the strafe attack was still going left or right, even if your ship was facing a different direction. This meant keeping it in would allow you to continuously charge for a speed boost on horizontal tracks.
This might have been fine, but when I came to the extremely late decision to remove AI racers altogether, it seemed totally out of place. I liked the idea of a charge boost but I ran out of time to make it work in the new context of the game. So, like AI racers, I ended up disabling it altogether for the jam release.
This meant the controls were woefully simply–left or right, nothing special–but after removing AI racers, it didn’t make sense to keep the attack in. This is definitely an area I can flesh out on further releases, where AI racers are a top priority for additional features, since they already kind of work.
Late Game Flow
One thing I did right in my first Global Game Jam and the GBJam earlier this year was to start with the beginning and the ending of the game, then flesh out the middle. I’d heard this was a good idea from a lot of people I trust, both at GDC and in books. Unfortunately, I forgot this piece of wisdom for LD34.
I stared with the middle: the racer moving up the track. I later added the countdown, then the finish. Finally, I made the racer select, title, and flow between races, in that order. This led to many problems, including the Crusher Bug which I wasn’t able to fix by deadline.
This basically halted the title screen camera from getting destroyed, resulting in all sorts of awkwardness including an immobile camera.
On top of doing this in the wrong order, I didn’t realize that Unity had deprecated the Application.LoadLevel() method. I could have used this method, but early on I’d made a pact with myself to do things right with the code, since doing otherwise had almost crippled my GBJam game.
Unfortunately, a Google search for “unity scenemanager” gives hits for an extension package, and not the official SceneManager documentation. Eventually, I was able to find the documentation, but it was kind of a headache learning the one little bit I needed to know to get it to work–that scene management is in its own namespace, Unity.SceneManagement.
Although it’s convenient to target Windows, this means the porting to other systems has to come later, and is often rife with issues of its own. I should have started with a web target in mind to reach the broadest possible audience, rather than saving this for after the jam. Next time around this should be an early priority.
The art for tracks reflected the original vertical design, in which there are only left and right walls. That was until I discovered that Tiled (in its super awesome awesomeness) allows you to rotate tiles. So, for one, I didn’t need to manually add the flipped right side tile, and for another, I could easily make walls on the top or bottom.
That said, I didn’t have time to make curved, slanting, or corner wall tiles. I was also kind of lazy and baked the walls into the road tiles. Really, the walls should be separate so I can layer them on top of the roads as I see fit. I’ll probably do that in a future version.
Minimal Testing Time / No Controls for Testing
I had very little time at the end to test the completed product, which was a huge mistake. I still don’t know if unlocking the Tech Rider really works, and i wasn’t sure the kinks were worked out of the second or third tracks. I made the third track really late in development–started the assets Sunday night, finished the track Monday morning–so I only played through the whole thing once or twice.
I added the path nodes for tracks 2 and 3 in the last hour of the jam time, so these were rushed and really spaced apart. As a result, respawning in these tracks sometimes results in jumping half the course.
As you can see from the image, there are a lot, but really not enough–especially on the upper part of the split in the middle.
I had no way to skip to a specific race quickly, which is another lesson: include controls to test the game. These are great, because they can later be refactored into cheat codes or unlockables.
What Went Right
What is there to say about this engine/editor that hasn’t been said before? Sure, it’s rough around the edges for huge, highfalutin AAA games, but for indies it’s a bloody godsend.
I’ve been trying to learn Unreal off and on for a while now, but it’s just so targeted toward huge games that it’s difficult to get into it as a solo developer. Unity is the complete opposite: I’ve always felt it was approachable. It’s easy to pick up new things, and all of it just works. And C# provides a whole slew of friendly stuff I can include.
One thing I hadn’t used before that was critical to getting the game done on time was PlayerPrefs. I came to the conclusion that the game needed some kind of “best times” tracking. Although I was still going to have AI racers at the time, this eventually became critical to making the game competitive at all, since this is the only way to judge your performance.
(You can see here that I should have made the track a little bit wider to hide the clear color on the left…)
PlayerPrefs is a wonderful class that automagically stores integer, floating-point, and/or Boolean data to the operating system for you. It’s trivial to retrieve this data. No messing about with files or OS-specific nonsense. Implementing a “best times” table was super quick because of this, as was implementing the unlockable Tech Rider ship.
Music & Sound
As early as possible, once I’d settled on a concept and developed a bit of functionality, I created as many sound effects as I could imagine. This was a great idea because hearing the sound effects over and over made me realize how grating and terrible they were. This left me plenty of time to rework the sound effects.
I made the music for the first track early, as well. Although I didn’t get around to fixing its issues, I was able to take useful notes on the music at different points in development which will help refine it. I didn’t get to the rest of the music until Sunday morning (around the 36 hour mark) so I didn’t have as many notes for those, and like I said earlier, I didn’t get to test the other two tracks nearly as much.
My early decision to have everything in the key of C or Cmin seems to have paid off. I don’t really know about this because I don’t have any feedback on the sound at the time of writing, but all of the sound effects (engine sound, crashing sound, countdown sound, etc.) are on the note of C, and all of the music starts with a C chord. In the case of the last track, it’s C minor. I’m still up in the air whether this was good, or it should have been A minor.
I’m also proud of the decision to create the ship select / high score theme first, then remix it for the title theme. The title animation isn’t nearly long enough for you to appreciate the full track, unfortunately, but you can have a listen here if you wish.
[soundcloud url=”https://api.soundcloud.com/tracks/237618978″ params=”auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true” width=”100%” height=”150″ iframe=”true” /]
Past the 36 hour mark, I put together a spreadsheet and saw how ridiculous my formulas for ship movement had become. I stripped this down to three stats: max speed, acceleration, and weight. This was still too complex for my tastes, as I kept balancing things up and down, back and forth, so I dropped the weight factor altogether.
Time Warper has better acceleration, Sky Crusher has better max speed, and Fly Killer is between them. Since Tech Rider is unlockable, it’s a bit higher in both stats. This gave me a direction to go not only with the stats, but with the machine design: Sky Crusher would look rounder and heavier, while Time Warper would be sharper and more streamlined.
This made a whole lot more sense with all the numbers. Even though some miscalculations and/or typos set the hidden values a bit wrong, it helped refine the design to something workable.
All right, so I basically made a bastardized version of F-Zero with Super NES Micro Machines graphics. But it sure was fun–and educational. I’m still working on the Mac OSX port, and considering a future Web port. I could do Android but that might be a while down the road.
I plan to enter the Compo for Ludum Dare 35, and these are the things I need to take away from the LD34 experience to make that one shine:
- Create sound, music, and graphics early so you can see the flaws in-game.
- Make the beginning and end first, then flesh out the middle.
- Ensure game flows from beginning to end periodically during development.
- Target web first.
- Use tile rotation in Tiled as much as possible.
- Separate logical tile layers (like walls) for ease of reuse.
- Test the whole thing as early as possible. Leave at least 3-4 hours for full game testing and fixes. Include “cheat” commands to make testing easier.
Check out Tech Rider here, and let me know what you think in the comments. I’d also love to hear your Ludum Dare experience or about any other LD34 games I should play.