LD 34 Retrospective
So, it’s the evening after the morning before… that would be the morning of the Ludum Dare compo submission deadline… and I figured I’d just jot down a few thoughts about my first ever game jam entry. I’m sure these things have been said in every retrospective ever written, but you’re here reading this so I’m going to stick everything I can think of in this post it’s somewhat lengthy, but as it’s my first time I have a lot of thoughts about the experience.
1. Look at the themes during the final voting round
I did have a look at the final round… I voted… but I didn’t really think too much about them. By that what I mean is, have a good think about each one and possibly sketch out some ideas for each. I didn’t do that. I can find nothing in the rules that precludes you from thinking about ideas or sketching them out… you just can’t create the artwork or code before the jam starts. When the theme was announced, my heart sank and I just couldn’t think of anything. Then I remembered sitting there this time last year trying to think of an idea for the theme “Entire game on one screen”. I’d pinned my hopes on snowman being chosen and I had a great idea for a game. I was really cheesed by the theme and I just couldn’t get into it, but I did think of other ideas and one stuck with me. Thankfully I’d thought quite a bit about it since and it fitted the Growing theme for this jam. So, look at the themes and begin forming ideas for each of them… even the ones you think will never get picked.
2. Be prepared
Sounds obvious, but if it’s your first time, plan ahead. I downloaded the library I was going to use on the Friday night. I’d never used it, the documentation was thin (or non-existent) in places and the first part of my Saturday session was spent reading through demos working on what bits of it I was going to use. Also, make sure you have all your tools installed and working 100%. I found a crucial component of the library I was using simply didn’t work as supplied so I had to spend time installing Lazarus to rebuild it. Wasted quite a bit of time there. Also, if you’ve not used a particular tool in a while, use it before the jam, refresh your brain, and get bookmarks in your browser to all the reference material you are likely to need.
Of course, being prepared doesn’t just extend to your tool chain and libraries… you’re gonna need to eat and drink, preferably without incurring too much of a time penalty so make sure you have some good healthy snacks around and easy access to drinks etc.
3. Don’t obsess about art
I spent the first four hours worrying about artwork. You can go one of two ways here (there are probably more but hey)… you can put up with your crappy programmer art if you’re bad at artwork (as I did in the end) or you can practice your art skills before the jam. But quality aside, good art doth not a good game make! I’ve played some amazing games that have OK graphics and I’ve played some shockingly bad games that have the most amazing artwork. There is no direct correlation between art quality and game quality… sure it helps, but it is not the most important thing.
4. Don’t obsess about art (or more correctly – don’t spend too long on the jam site or Twitter)
Why is this item in twice? Well it’s true, the title is similar granted, but actually this point covers a broader topic. Social media. I nearly tweeted several times “Note to self, don’t look at other entries… it’s a ploy to waste your time and demoralise you”. Of course I know it’s not a ploy, but when it starts to get busy on the #LDJAM tag, it’s easy to sit there with TweetDeck open and watch as people start posting screenshots and other media. Whilst it’s nice to see what other people are doing, it can be pretty depressing since it inevitably leads to serious feelings of inadequacy and it robs you of your time to boot!
5. Don’t bite off more than you can chew
Obviously I’m biased, but my idea was great It fitted the “Growing” theme lovely and I would go so far as it fitted the other winning theme (“Two button controls”) as it only uses two buttons (plus the mouse) and also the non-violent combat theme since you use stealth to fight with the wasps and you don’t actually kill them. However… the finer points of implementation… what a nightmare (I’ll cover that a little later). The principal was simple… feed your tree, get your flowers pollinated and then protect the apples that grew from the pollinated flowers. Tree levels up, rinse and repeat up to a maximum of 6 levels in this version. Pollinating, that should be trickier than it is… the bees are spawned to fly past and because of the limited time, they fly in a straight line (if you discount the sine wave wobble on them). The flowers have a flirt mechanism that is designed to grow their sphere of influence and convince the bees to fly to them, but it’s just not needed. It should be, but I just didn’t have time to implement a more complex flight dynamic that would have made it a useful feature. Overall, I spent time on things that were simply not needed to make a fun game because I over stretched myself with an overly ambitious implementation of my idea.
6. Design first
I know a lot of us don’t like designing, and when you’ve only got 48 hours it’s easy enough to say screw it and skip the design phase, but I wasted a lot of time restructuring code to maximise reuse. Get an idea, sketch it out, and then put a design together. By all means change it later if it doesn’t fit, but at least spend some time thinking about it before you start coding. Try and make it easy to extend (more on that later).
7. Have fun
If it gets too stressful, just remember it’s meant to be fun There were times I could have smashed my head on my keyboard (not because I fell asleep), especially in the last few hours, frantically trying to fix the myriad of issues… in the end I had something that illustrated the concept I was going for. It’s far from even being called ok, but from a concept point of view, it’s demonstrated to me that the idea is valid and it has the potential to be quite a good game. Plus, I tweeted a little, read about other peoples antics and I saw how much I could achieve in a short space of time, I had a good laugh with Spirit as she watched me plod on and I felt like part of a mad family of crazy people who all just want to make games. So all in all, I had fun. It won’t win or get anywhere close to a ranking (if it does I’ll think I’ve entered an alternate reality) but I learned some stuff and had a blast and I’m looking forward to the next time
8. Keep an eye on the time
When you see some of the entries, with nice sound, good graphics and music… I just wonder how these peeps do it all in the time. I tried sounds, they sucked and got dropped. Music… yeah, I listened to music during the jam… oh wait… you mean in-game music? Not a chance in hell would I have had enough time. I think I slept for 10 hours, spent a couple doing domestic things and eating… other than that it was head down grafting. And the last 4 hours… what last four hours? Last time I looked at the clock it was around 10pm, next thing I know I’m nearly missing the deadline. Keep track of the time and don’t leave yourself too much in too little, which kind of ties in with no. 5 “Don’t bite off more than you can chew” although that obviously also relates to technical challenges.
9. Take a break
Yes you’re against the clock but I found that taking a break helped. I spent an age chasing a ‘bug’ that meant the bees didn’t fall in love when they pollinated a flower. Turns out I was setting the ‘inLove’ property of the wrong object… it wasn’t even a bee!!! Typecasting is great, but god knows what piece of memory in the object I was zapping with this. Finally sorted it when I had a short break and came back to the code. Flicked to the source when I was setting it and *BLAM* I spotted it immediately… I wasted about 2 hours trying to figure out why it wasn’t happening and it was all down to me. So, if you get in a rut and just have a brain full of cotton wool, move on, do something completely different for a short while and see if it helps.
As I said at the beginning… these points are likely to pop up in any jam retrospective. They are pretty much common sense, but when the pressure of the deadline is there, it’s all too easy to get bogged down in the event and forget the simple stuff.
And so it’s time for a bit of a code review… I’ve already had a hint from Al González (@algonzalez74) on Twitter… “@AthenaOfDelphi Use a enumerated for “fTreeState : integer;” ;-)” And he’s absolutely bang on, there are numerous state machines within the code and none of them use enumerated types for their state. I think I was being lazy, but in the end it cost me time. If I’d used enumerated types I wouldn’t have had to renumber my constants when I changed the states (I know you can get away with just adding another but my OCD kicks in and I have to renumber to keep them in the order they are normally used). Oh if that were the only problem
I’ve mentioned that you should design… and really you should.
I knew roughly what I wanted to achieve right from the outset but I just didn’t give the code enough thought… so the first thing I did was to create a TWasp class (or something like that) to represent the wasp critter. I got that flying on the screen, was chuffed and moved on. Then thought I’d add a wasp flying the other way, to add variety.
So TWasp became TWaspFlyingLeft and TWaspFlyingRight with a common ancestor TWasp. The only difference here is that the constructors of the children are different to set some parameters that are used for the drawing and processing in the parent TWasp. That was simple enough, then I went and drew the art for the bee and came back to the code… ARGH!!! Now I have another flying critter and so the class structure for the flying critters went on it’s final journey that sees it all stem from a class that implements the basic TFlyingCritter. This has two children, TCritterBee and TCritterWasp which in turn have two children each to represent the left/right flying variants. In essence, the various types just initialise a bunch of fields within TFlyingCritter to achieve the desired result. I could have done this when they are created, but then the class using them needs to know more than it probably should about the items (such as which frames to use for the animation etc.), which is a bad thing because changes to the flying critters may require changes to the class using them.
The obvious upside of this is that it allows you to use type casting, so I can have a list of flying things and it’s easy to iterate over them checking for collisions etc. Plus it’s easy to add new flying critters by simply extending the appropriate class.
I applied the same sort of structure to the items on the tree. They all descend from TMyItem (so called because the tree is TMe… I Am Tree) which provides a common interface… things like ‘nerf’ and ‘action’. When an apple is actioned it goes into stealth mode and hides, when a flower is actioned it flirts. The items are basically state machines to handle the animation switches etc.
At the top level, the game uses a state machine… it has TIAmTreeController which is a master state machine for the program. It currently has three states, Intro (TIAmTreeIntroController) In Game (TIAmTreeGameController) and Game Over (TIAmTreeGameOverController). Each of these implements several draw methods and a timer method which are called by the main controller. This was a nice approach as I was easily able to slot the intro and game over mechanisms in at the end (until that point, when you ran it the game went straight into game play because that was the only controller that was used).
If you’re not familiar with state machines and you’re planning on jamming at some point, then learn them. They are incredibly useful yet incredibly simple beasts and the code for I Am Tree is littered with them.
Overall, I’m pretty pleased with the code although there are still some places which know too much about things they probably shouldn’t. TIAmTreeGameController for example, knows about the items on the tree and it iterates through them for collision checks. What should actually happen is, it should feed a list of bounding boxes into TMe (the tree class) and have it do the work. As it is, I can’t just rip TMe out and replace it with a much better implementation.
All that said though, I’m pleased with what I achieved in the short amount of time. I’m disappointed some of it isn’t as neat as I would like it to be, but hey. The feedback I’ve received thus far suggests the idea is worth exploring further.
What went well
- Fun… I had a blast
- Work level… I learned that I can achieve quite a bit in a short space of time if I put my mind to it
- Skills… I started to learn how to use some new tools
- Code… I’m pleased with the underlying code structure (mostly) because I can rip bits out with minimal impact elsewhere although some parts are just hideous
What went badly
- Sleep… I’m still tired
- I should have thought more about stuff before I dived into code as I wasted time restructuring to make reuse and common fixes easy
- Sound… what sound? It did have sound but it was awful for a variety of reasons
- Art… my artwork sucks. I need to practice (ALOT)
- Sizing… things are all out of whack. The flying things are huge compared to the tree and the flowers and apples are minuscule considering their importance to the whole game play mechanic
Based on the feedback I’ve received thus far, most people get it and are able to figure out the mechanics others are not. In rating some entries I’ve been frustrated by the lack of clear mechanics and a lack of instruction, I should perhaps remember this and have another game state (TIAmTreeTutorialController perhaps) that walks people through the whole game play process. I originally intended to have multiple trees and a lot more complexity in the game play in relation to apples and the critters but there simply wasn’t enough time for it.
Will I develop it further? I suspect so, as I say, I do have quite a few ideas for improvement
Overall, I consider my first game jam to be a success and I look forward to the next one I take part in.