Ok, final post on BallZup since it’s now out and in the wild.
Quick sales figure update. Based on the weekly reports, the demo version sold 295 copies up to the 23rd of November. In the two days the full version has been up (at the 3.99ukp price point), I’ve shifted 30 copies. This is with no reviews or press of any sort really, just appearing in the new releases section of the App Store and getting listed in the large collection of App Release aggregators on the web.
The figures are pretty consistent for the demo. While it’s in the top 25 listings for new releases on the app store it shifts 25+ copies a day. Once it drops off that list it does about 4 or 5 copies a day, if that. This pattern has been pretty much the same for the 3 updates I’ve put out, so you do need to keep bouncing your application with new releases.
Updating at the weekend doesn’t seem to make any difference to sales. In fact, this weekend they dipped compared to the mid-week update I did for 1.2. So, it’s a bit hard to figure out if there’s a more attractive time to be visible. Updating on a Monday morning seems to work best for me atm, as I’m normally in the store on Weds and squeeze 2 days in the list. Of course, everyone else is up to the same trick, so if you’re unlucky, 25 other games have been updated, you’re the first to get listed and fall out of the hot zone straight away. This happened to the full version’s 1.0 release this week. Probably because I was Ready For Sale on Weds afternoon, but opted to hide it until Friday.
Some Stuff That Went Wrong
Few lessons learnt from the whole experience:
Nicking Apple’s Crash Landing Code: I used this as a framework for the port from the Unofficial Tool Chain to the Official SDK, completely replacing all my software rendering and png loading with the texture2d class and OGLView setup in that demo. It gave me a great kick start on the port but had a few problems:
- The double buffered contexts would randomly corrupt at runtime. I was never able to reproduce this in the debugger although it was ever present in the 2.0 SDK. It only ever appeared on the actual hardware as well… I thought it’d had disappeared when I moved to 2.1, but it popped up again on the final release version, meaning I had to completely replace the OGLView classes at the last minute. Not a huge task, but it was annoying. No idea what caused this but I think it might have been a timing issue somewhere, probably in my code
- The sprite class ended up being split between ObjC and C++. Lots of function overhead I could have avoided and in the end it actually restricted some of the stuff I wanted to do. I also couldn’t take proper advantage of the OGL state meaning there are too many texture binds, and I didn’t spend the time to make sure all the blended blits were done at the last pass. On the next game I’m going to use a single texture page, get a bit more flexibility with the UV co-ords and manage the blit orders myself to squeeze them all out in one lump… I should have just spent the time to do a proper sprite/draw manager and decoupled this more from the game logic.
I’d been pretty good with my C++ code for most of the project, but once the game was essentially complete and I was adding niceties like the score upload and saving, stuff got messy really quickly. This is due to a complete lack of thought/design as I’d been dealing with the ObjC as setup and the C++ as “my game”, not thinking about how stuff was actually communicating until too late. But for future reference I should have:
- Spawned different classes so I could properly delegate UI messages in the ObjC, or just handled it as part of my game-state in the C++ side. The latter would have been tidier, the former probably quicker to write.
- Batched up the responses from the Async stuff like the score upload and only handled it when I was ready to, in the game. Like the input events. What I ended up with is a fucking mess of conditional code in delegate functions that really shouldn’t be there. And some very hacking state changes for the game…
The other massive downside to all this was my lack of knowledge of ObjC. Lots of time was spent working out the magic voodoo that would convert Apple’s core types to something I could use, or formatting my stuff into something the Apple stuff would use. I understand a lot more about all the core types now, and it’ll be a lot easier the second time around, but toward the end of the project a lot of time was spent googling…
And then, right at the end, I learnt a big lesson about having a clean XCode project. It took well over a day to get the provisions sorted, have the build compiling with the right code signing and build a version for release. Not to mention learn the nuances of the iTunes Connect process. This is all easy now, but it was a hair pulling day of frustration when all I wanted to do was release a version…
More minor stuff:
- My textwriter is rubbish…
- Speed could definitely be better. 46-50fps avg in the profiler isn’t good enough really.
- I never did fix that click in the audio
- I really really should have put in an option for save and quit after every level. So people could restart when ever they wanted
- And because I can’t save state, the game quits when a call is received.
All of which I’ll fix for the next game
But Stuff I Am Quite Happy About…
- Getting it done
- Nicking Gaz’s interface setup. The Mac version fell out in a couple of hours…
- The collisions! Line intersections melted my brain for 2 days but proved solid as a rock once running.
It’s actually quite playable in the end. And I do like the multipliers.
If you treat it as a high-score run, then you do really need to use stuff like the Minty Saves and free Zapper to manage your ball speed and give yourself a chance of maximising the multipliers from a level. Small things, but enough to make me pleased with the result.
It sounds good (although K hates the intro level tune, thinks it sounds like a game show, which has only made me love it more) and it looks a lot better than I thought it would. Big props to Gman for tarting up my initial stuff and a big Woot for OGL. My SW rendering stuff just wasn’t as tasty in the end

