Project Post Mortem – Zombies Hate Pumpkins DX
This is part 2 of our AIR Post Mortem – part 1 is here and deals with the pros and cons of using Flash to develop mobile games.
Zombies Hate Pumpkins DX was our first mobile project as Monster and Monster. The idea was to take a game we’d already made and spend a couple of weeks sprucing it up and then rebuild using the new CS5.5 packager for iPhone.
The original Zombies Hate Pumpkins was a web and Android game that we’d thrown together fairly quickly (about 2-3 weeks work if I recall) for Halloween 2010. This was pre-Monster and Monster so the game was released as a collaboration between GrizzlyMrDan (me) and Electronoodle (Dave).
We released the web version on Kongregate and used Mochi distribution to set it loose on the web in general. The Android version we put on the Android Marketplace for free to see what would happen.
Our plan for the DX (deluxe) version was to add a couple of modes, Facebook support and some new visual effects (i.e. just enough to make it worth paying for) and be done within the month.
At the start of the project I was still doing things the old-fashioned way. I was using the Flash IDE to compile and FlashDevelop was pretty-much just a code editor (the best code editor ever!)
After a couple of release builds done this way I upgraded to the latest stable version of FlashDevelop and re-jigged the project to build entirely within FlashDevelop and now I’ll never go back. There were quite a few problems transitioning the Zombies code but I’ll get to that in the ‘What Went Wrong’ section.
All the versions of Zombies before 2.0 were built with the CS5.5 packager for iPhone. From 2.0 (onwards?) they are built using the FlashDevelop packaging tools which I believe are essentially just custom batch files that wrap the Flex SDK.
What Went Right
For starters we made a pretty good game that we’re proud of!
If you’re a Flash developer yourself you know how difficult it is to create an action game in Flash that maintains a steady framerate and good level of responsiveness, and by and large we did it, on the iPhone too, which has a less than optimal version of the Flash Player.
Dave and me did everything in the game bar a small number of sound effects (most of the sounds in the game are courtesy of Dave’s mouth [ Grrrrrrg...arrrrrrrgggg – Dave ] ) and that makes us feel proper indie.
While I was messing around with code and taking much longer than we’d hoped, Dave created a bunch more zombie types. One of which was the ‘fat one’. It seemed pretty obvious to us that he should be harder to kill which is why he takes two pumpkins to take out. We’re really pleased with how he turned out. He’s full of character, adds an extra tactical elements to the gameplay and in Classic mode, he’s genuinely terrifying!
Zombies DX adds loads of visual effects. We’re particularly proud of how the classic mode storm worked out – it was a lot of work from Dave and me. Dave had to jump through hoops to get the animation working because my rendering code had to be so tight it really limited the tools and approaches Dave could use and even then I had to rethink the renderer a bit to keep the framerate up. The fire and ice pumpkins also required a lot of tweaking and optimising and again lots of extra work for Dave but the end result is very satisfying!
We’re very proud of the audio design. Most people will probably play with the sound off or only though the iPhone/iPod’s built-in speakers. But if you do use headphones you’ll hear all the dynamic panning and volume scaling tricks we’re using. [ I still think good audio design is an essential element to a great game. It can add so much atmosphere and context and I was really happy with the way we planned out our audio at the start of the project - Dave ]
The Apple submission had its issues (see ‘What Went Wrong’) but we were lucky that the first build we sent to Apple went straight through submission with no problems. I think that it helped that we’d been warned that Apple could be difficult to please and we read up on all the horror stories and ‘do’s and don’ts’ of App Store submissions and took it all on-board. We finally went live a few days before Halloween 2011 while we were at Nottingham GameCity.
Gameplay changes from the original game
As a former game designer, one of the important things for me was to get the gameplay to ‘feel’ better. The original version of Zombies was fun enough for a while but didn’t quite have that hook – for some reason it just didn’t make you want to chase your score. I knew the game design was sound and it was a bit frustrating that it wasn’t quite as fun as it should be.
The original Zombies game used a fairly simple system to spawn zombies, basically just picking a random column to spawn a zombie in with a random delay between spawns and a system to ramp-up the difficulty over time.
For Zombies DX I designed a much more ambitious system. What I came up with was something I pretentiously called ‘The Director’ – though I may have stolen that from a Gabe Newell interview from several years ago…
Anyway, my goals for the director were:
- To give beginner players a gentle introduction
- To give expert players a fast ramp-up so repeat plays don’t spend too much time in the early ‘easy phase’ before getting to the part where you can really start racking up combos
- To increase difficulty in different ways as the game progresses, so it’s not just more/faster zombies – e.g. there are new formations that need to be dealt with in different ways as the game progresses
- To create an ebb-and-flow of difficulty – e.g. take the player to the brink of failure and then suddenly cut them a break and give them a chance to get back in the game
- Make the zombie kill order a more tactical decision than it was in the original game
The first two points were dealt with by having the difficulty increase based on time passed and the players score. This works well because beginner players tend not to get their heads around the combo system and so their scores increase very slowly, the time passing tends to be the main factor in the increase in difficulty. Experienced players generally understand the combo system and within literally a few moments their scores are sky-rocketing which means their score is the biggest factor ramping up the difficulty. Obviously there’s potential to effectively punish good players for building their combos up too quickly, creating a tactic/potential exploit where good players drop their combo periodically to keep the difficulty down and play the long game – this was basically just a case of tweaking the relative influence of time and score on the increase of difficulty and was achieved through a lot of playtesting.
Keeping the increase in difficulty interesting was managed by splitting difficulty into its separate elements. This effectively boiled down to how fast the zombies move (which is actually a range from min/max which can both change as difficulty goes up), how many zombies can be onscreen at any given moment and which formations are active. Each of these elements has its own level – e.g. zombie speed level, zombie count level, zombie formation level. And each of these elements can ‘level up’ when the difficulty system deems it appropriate. We tweaked these ‘level up’ criteria so that they happen out of sync to keep things interesting for the player.
The patterns that the zombies appear in are not random. They are authored formations that the ‘director’ picks from. We rated each of our formations for difficulty and the system picks an appropriate formation based on the current formation level.
The final thing was the ‘back from the brink’ feeling. This was implemented by detecting certain conditions that indicate the player is struggling and giving them a temporary reprieve while they get their heads back together. There’s a system to make sure that reprieves don’t happen too frequently just in case players get wise to what the reprieve conditions are. A reprieve effectively knocks all the difficulty levels down for a short while before they return to their original values.
We also had a ‘happy accident’ at one point. A bug in my code meant that some zombies were being updated twice per frame, effectively meaning that they moved twice as fast as a normal zombie. When I fixed the bug we realised that actually those sprinters had really added something to the gameplay, so I added a small random chance of creating a double speed zombie into the director.
If that seems like overkill for a fairly simple arcade game you might be right. From our POV though, Zombies went from being a game that ‘should be more fun than this’ to something that was actually stealing productivity from us because we’d get carried away playing it when we were meant to be testing it – so in my mind, worth the effort.
What Went Wrong
Biggest thing was it took waaaaaaaaay toooooo looooooong. A project that was meant to take a couple of weeks ended up taking 3 months. We all know that software is a tricky thing and game projects in particular always take longer than expected but this was a whole new order of stupid. To be fair to us some of the things that happened we couldn’t control and some of them were personal rather than strictly down to our planning and rather haphazard approach to project management. Most of the things discussed in this section will be the time sinks and hold-ups we encountered. Luckily we learned from many of them which is how our follow-up project ended-up being completed so quickly, but I’m getting ahead of myself now…
Underestimating the impact of the changes we wanted to make
For starters neither of us had realised how long it would take for me to be happy with the gameplay. It took me the best part of two weeks to design and implement my Director code. That was most of our ambitious schedule taken up already.
Then we hadn’t accounted for the fact that the game modes we were thinking of (although only slight tweaks to the core gameplay) would require their own set of tweaking parameters – and we all know how long gameplay tweaking can take.
I had the dilemma that since I hadn’t planned in multiple game modes in the original implementation, I didn’t have an obvious way to separate my existing code into multiple modes. I guess if I’d planned it from the start I would’ve used inheritance with derived classes for each mode based on a base class that had the basic game functionality in it. As it is, I chose the quick/dirty route of putting ‘if gameMode == blah’ all over the place. This means I was forcing quick/dirty hacks on top of a game that was originally a quick/dirty hack of a project. Basically, quick/dirty hack squared which eventually bit me in the arse. End result, not so quick and very, very dirty.
There was quite a lot of ad hoc design throughout the project. Quite a few times I’d begin to implement something that seemed like a small feature, only for the full range of consequences and knock-on effects to gradually dawn on me – usually at the point where I’d already got so far into it that undoing my changes didn’t seem like an option. Dave got quite used to my head slumping into my hands at these moments and he would usually make me a nice hot cup of tea (thanks, Dave). I think the easiest thing to fail to account for when adding new features is how many new menu screens you’re going to need to create. I’m glad that I wrote my framework to handle menus pretty well – if we’d been using the old-fashioned Flash way of putting all your menus on the top-level timeline this would’ve been far, far worse.
The visual effects we wanted to add actually required some major changes to the renderer. This is worth going into more detail on so I’ll put that in it’s own section.
Adding facebook support ended up being a nightmare on a number of fronts. I’ll go into this in more detail under its own heading.
I guess I could’ve summarised this as ‘even trivial-seeming projects should be properly designed, estimated and scheduled’ but I guess I just wanted to share some of our pain.
Not switching to FlashDevelop soon enough
We didn’t get far into development before compile times became an issue. Using the Flash IDE for compiling, in retrospect, cost us a lot of time. The problem with the Flash IDE’s way of compiling is that it builds everything from scratch every time, even classes that haven’t changed, worse still it rebuilds all of your assets, which means converting bitmap data, compressing the audio files, transcoding any video etc. By the time we were about halfway through development compile times were 10-20 mins. Imagine trying to fix bugs and tweak gameplay etc. with compile times like that. Like an idiot I just soldiered on!
When I did finally switch to FlashDevelop it was a world of difference. When you work with FlashDevelop as your compile step things work differently. For starters you compile your FLA file only when you change any assets. This means all the bitmap/audio/video encoding is only done once in a while, instead of every build. This alone makes builds about ten times faster. Also FlashDevelop’s compiler is much smarter and only compiles classes that have changed before doing the build step. Suddenly 20 minute builds are happening in 5 secs! Version 2 of Zombies had it’s issues but at least compile times weren’t one of them!
Transitioning from the Flash IDE to FlashDevelop was not without its problems and at various stages I thought it wasn’t going to be possible. Over the years of working with Flash I’ve developed a range of techniques that work very well for IDE-based projects but not so well for the way FlashDevelop works. One of the biggest issues was that in a FlashDevelop project your FLA file is not meant to have any code dependencies – this makes sense because if it does have any dependencies then you will have to recompile your FLA whenever the classes it depends on change and you could be back to square one. My main FLA was full of dependencies and I had to go through one at a time, removing them all. There were a couple of other caveats as well that I had to discover through trial-and-error. However, I did get there in the end and it was worth the effort ten times over.
Facebook integration a.k.a. Aaargh no, kill me now..!
Dave and me read about the Facebook SDK for Flash. Created in a collaboration between Adobe and Facebook, it is the recommended way for Flash apps to communicate with the Facebook API. I looked into it quickly and it seemed like the real deal, with a clear interface and a large community of users. It sounded easy enough which is why we decided to go ahead with Facebook integration as a new feature.
We left Facebook integration out of version 1 of Zombies DX because we weren’t going to get it done by Halloween otherwise, we delayed the feature until version 2 – which meant it ended up being the main feature of v2.
There turned out to be a lot of problems with the Facebook SDK. For one thing it was very difficult, not to mention time consuming to work out which parts of the Facebook API were actually supported and which weren’t. The API was very unclear that different Flash platforms would behave differently and that some functionality wouldn’t be available to us as AIR mobile developers. It also took a lot of reading, experimenting and trial-and-error before I worked out that large parts of the API were off limits to us because we wouldn’t be able to embed the ‘App Secret’ in our game code – in particular we wouldn’t be able to use the Game API features (this is surely a case of Adobe/Facebook shooting themselves in the foot!)
Once I’d spent a number of days exploring various dead-ends it became apparent that as an AIR mobile developer we were going to be limited to very basic Facebook interactions. Essentially limited to getting users’ names, profile pictures, friends lists and posting status updates. I guess we should be grateful that we could get friends lists though as without that the friends score table wouldn’t have been possible.
Once I started using the SDK it became apparent that it doesn’t do much for you. Really it boils down to one function which sends a string to the Facebook OpenGraph API. Responses are handled by callback functions rather than using the standard ActionScript event model – to me this is a bit peculiar – the situation is made worse by the fact that the function prototypes for these callbacks are not documented in the SDK reference and you generally have to Google some example code that shows the correct prototype to use which was just pointless time-wasting from my POV.
We added a feature that allows people to post their scores on either their wall or the walls of their friends. We hoped this might help spread the word of the game. However, Facebook sometimes blocks wall posts from apps unless the user attempting to view the post also has the app installed. This was disappointing for us as people trying to promote a game, but honestly as a Facebook user the fact that ‘game spam’ has pretty much disappeared from my news feed is quite a relief so I guess I can’t really complain. Also, I’ve noticed that most normal people don’t like posting these kinds of notifications from games anyway – this feature has only been used by a couple of our friends who were probably just doing it to show their support – which is why we love them.
I also implemented a hiscore database on our own server. This database stores a user’s Facebook UID (user id), their score and the mode they achieved the score in. This database is then cross-referenced against the Facebook API to create the list of global and friends’ scores. I wrote a class that bundles all the hiscore and Facebook API stuff into one module for reuse in future projects – I’ll let you know how that pans out. The hiscore system has also been woefully underused. I get the feeling that average game players are either not interested in being competitive in this way (it is quite old-school I suppose), they don’t want yet more crap plastered all over their Facebook page or that maybe that the Facebook functionality isn’t signposted well enough from within the game.
To summarise then; the Facebook SDK was oversold to us, it almost drove me mad trying to get it to work and then no bugger used it!
Rendering and optimisation and that
As mentioned, the Flash renderer is slow. It’s also a bit of a ‘black box’ with very few people genuinely knowing what happens inside. Doesn’t stop a lot of people trying to give advice. As usual best thing is to test your assumptions before rewriting huge chunks of your game code.
When we started the original Zombies Hate Pumpkins back in 2010 the recommended approach for decent Flash rendering performance was what ActionScript programmers call a CopyPixels engine. CopyPixels is the name of the function in Flash that allows you to copy raw bitmap data between draw objects – effectively blitting in more general game coder speak. This is the approach I took in Zombies.
CopyPixels engines are actually a pain in the arse for a number of reasons. Mostly you lose loads of built-in functionality such as scaling and rotation of sprites. You have to deal with things like z-order and you can’t use any of the neat Flash features such as hit testing and mouse handling. From an artist’s POV it’s even worse since you can’t use timeline animations any more, everything has to be sprite sheets and they’re much harder to work with (sorry Dave!) Anyway, for better or worse Zombies uses a CopyPixels renderer so we just had to man-up and get on with it.
Originally the game was intended to run at its native resolution. In order to get that chunky pixel look I upscaled all the bitmap assets (without filtering) in code as the game initialises. I thought this would be faster than either scaling as I rendered each asset or by upscaling the entire scene after the render is finished. This actually turned out not to be true, though it’s still hard to say exactly why.
I had to optimise the renderer when we added the rain to classic mode. I realised that the easiest things to implement that might make a difference would be if I could reduce the number of blits per frame or find some way to make the blits faster. The first option was out of the question, if anything I’d need to do more blits to add things like rain splashes to finish the effect. That meant finding ways to blit quicker. I did some benchmarks and found that the size of the blit (in pixels) had a very big effect on the blit speed – fill rate was the problem basically. So I abandoned the prescaling of assets and rendered them at their native size – because I was doubling both dimensions before, this now meant I was only rendering a quarter of the number of pixels per frame and this gave me the framerate boost I needed. To compensate I had to double the size of the end result of the render but I left this under Flash’s control and this seemed to have no effect on the framerate – I suspect this is because the Zombies app itself has to be scaled to fit most devices’ viewports and flash was doing some clever transform maths so that one transformation was being applied to the game canvas that took into account the fact that it was being doubled in size and that the parent app was also being scaled – er, meaning that somehow the game content got magically scaled for free.
I also added BitmapData.lock and BitmapData.unlock commands to my renderer which seemed to help too – the performance improvement maybe be down to the fact that I could now remove my double-buffering code which removed one full-screen blit per frame.
I did some game logic optimisations, some of which broke game logic, actually slowed things down or eventually had to be undone again for other reasons. The game logic optimisations that actually noticeably helped were using Vector classes instead of Array and iterating with ‘for each’ loops – this actually had the pleasant side effect of making the code more readable (which is unusual for speed optimisations). I also improved the ‘feel’ of the game by separating the game logic and rendering updates which is a fairly standard trick – if a frame takes too long to render then the game logic can be called multiple times to catch up – this means even if the framerate drops, the game runs at the same speed – it’s a fairly standard game programming trick but not many Flash developers use it.
This section is in the ‘What Went Wrong’ category because, given recent developments (particularly in AIR 3), CopyPixels engines may not be necessary any more. Adobe have improved their GPU mode support now – this means the Flash native Bitmap class now renders blisteringly fast (by Flash standards…) and CopyPixels can’t get the full benefit from this improvement at the moment. In a perfect world Zombies would probably never have used a CopyPixels engine and we’d have got it done much quicker. Disappointingly I tried Zombies with GPU mode enabled – although it did run a little smoother, for some reason the game renderer ended up being blurry, like the upscaler was applying a filter which spoiled the retro look we’ve gone for.
App store submission
Mostly this actually went right even though it didn’t feel like it at the time. Apple’s developer portal is a mess, the help is distinctly unhelpful and the system they have in place is really complicated. I mean it probably makes sense and all those certificates and device ids, app ids, provisioning profiles and whatnot are probably all necessary and so on, but having published two games on the App Store and done multiple updates on both projects I really have barely a clue how it works.
Getting our first version of Zombies uploaded alone involved a lot of head scratching, Googling, more head scratching and I hate to say it but some curse words were uttered during the process (sorry Mum).
There are a few things that you need to know as an AIR developer that might not be immediately obvious:
- First you’re probably a Windows-based developer because lets face it the Mac version of Flash is terrible and FlashDevelop hasn’t been ported to Mac yet, so that means you will have to buy a Mac (unless you want to break the iOS developer agreement and run a virtual OSX box) – we bought a Mac Mini.
- Second, applying to become an Apple developer as an individual is fairly quick and easy and you could be ready to go within hours of applying. Applying as a company can take up to three months and will involve faxing your certificate of incorporation to the US (yes, FAXING!), an international phone call or two and possibly a trip back in time to change the constitution of the United States of America.
- Third, the IPA files that the Flash IDE and FlashDevelop create for you will deploy directly to an iPhone/iPod/iPad for testing but they will not deploy to the App Store. There are instructions online for making the necessary conversions but to be honest they filled us with confusion and fear. What worked for us was to build the IPA on our Windows machine, copy it to our Mac using a USB stick, once there rename the IPA as a ZIP, unzip it and then zip it again on the Mac and then (leaving the .ZIP extension as is) upload it using the Apple Application Loader.
Sometimes the Apple Application Loader will throw scary sounding errors that makes it sound like they’re onto you and your dirty Flash programming ways – whenever this happens we want to hide behind the sofa – but in most cases we just needed to reboot the Mac and try again – why this solves the errors we will probably never know. Sometimes Apple’s website will tell you things haven’t worked, or you haven’t signed this or submitted that. This is because the Apple website is toying with you. If you give it a couple of days and come back later it will probably be working and you can stop crying tears of anguish and start crying tears of joy instead.
Once we got around the logistics of the uploading the binary and filling in all the forms etc. everything else was plain sailing.
The lessons to take from this experience are:
- Apply for your developer status ASAP
- Don’t leave App Store submission til the last minute – it can take up to five days for an app to go live even when you know what you’re doing and the Apple website is feeling benevolent
Anyway, I put this in the ‘What Went Wrong’ section because it took way longer than we thought and caused us both a lot of stress – it’s just through happenstance that this last hurdle didn’t push us way past our original Halloween deadline.
What we’d do Differently
- Design, estimate and schedule the project properly from the start
- Build in FlashDevelop right from the start
- I would probably handle Facebook interactions via our server using PHP rather than using the AS3 Facebook SDK – this wouldn’t add a huge overhead because we need to contact our server to get score data anyway
- Leverage the GPU accelerated mode in AIR 3 and render our game objects as Flash Bitmap instances – not just for performance reasons but also for art/animation workflow and ease of coding
- I think there isn’t much we can do to streamline the Apple submission process other than schedule plenty of time to get the app live to allow for technical hiccups and maybe even a rejection or two to be on the safe side
In part 3 we discuss our Victorian Constitutional Simulator that we finished in record time.