A bit over a month ago [1], I decided it was time to create a “lite” version of Flower Garden [2]. I really thought it was going to be a pretty easy task: Disable a few pots, remove some seeds, and repackage it. Sounds simple enough. But before that, I had to decide how to structure the project for the lite version.
#defining The Problem
The first approach that came to mind was to use #ifdefs. Hopefully, if I did things well, it wouldn’t require too many of them. As soon as I gave it some more thinking, it was clear this was a pretty flawed approach.
I like to be able to create a build with zero human interaction: Press a button, wait, and the build is ready. I don’t want to have to do any manual (read, error-prone) steps. So I couldn’t just have an #ifdef that I turned on and off depending on whether I was building the lite version or the full one. I can get around that by creating a new configuration in XCode, except that it wouldn’t be one, it would be one for every existing configuration I already have: Debug, Release, Distribution Ad Hoc, and Distribution App Store. So this would make a total of 8 configurations. That’s rather ugly!
In case the explosion of configurations wasn’t ugly enough, there was one other, even bigger problem: An #ifdef wouldn’t allow me to change the assets included in each version of Flower Garden, and, most importantly, I couldn’t change the Info.plist file to have a different bundle id (although maybe I could change the Info.plist for each of the new configurations and point it to the new one).
Not an attractive option. So how else can we do it?
New XCode Project
The idea is straightforward: Make a copy of the existing project for the full version of the game, and change it in any way you want: Remove resources, add new ones, change Info.plist, etc. You can still share common source files and define a preprocessor macro LITE in the new project to #ifdef parts of the code.
This approach sounds more promising, until you realize that changes made to one project don’t carry over to the other one. So if you’re done developing the full version, and you create the lite version at the very end, maybe that won’t be a problem (although, how can you be sure you’re done?) And making changes to two separate projects is never fun.
You could improve things a bit by starting out the lite version as a branch in source control. That way, changes made to one of the branches can (hopefully) be merged back into the main line or another branch (have fun merging xcodeproj files). I think it’s because I’ve had the displeasure of working in projects that went totally overboard branching, that just the word branch makes me recoil in disgust. Yes, this method might work, but it seemed cumbersome and error prone.
Any other solutions?
Stay On Target
It turns out I kept thinking in terms of a solution I could have implemented in Visual Studio (that’s what I get for spending so many years working with it). But fortunately we’re not in Windows-land anymore. This is XCode, and XCode totally rocks.
XCode’s build system, once you wrap your head around it, is much more flexible and natural than Visual Studio’s. It’s much more like a make file (and I say that in a good way–I do like make files!). You have files, and then you have targets. And there’s nothing that says a file can’t be in multiple targets (and the file only appears in the project once). Once you have multiple target, whenever you add a new file you have the option to add it to both targets the same time if you want. Perfect!
My Flower Garden project contains about 15 targets: 7 “engine” libraries, 7 test executables for each of the libraries, and one main executable target for the game itself. So the (now obvious) solution, was to simply create a new target for the lite version, in that same project, with the same files. It turns out this solution had all the advantages of the previous approaches with none of the drawbacks.
Lite Target Details
Once I landed on the target idea, it really was quite straightforward to create the Lite version by following a few, simple steps:
- Make a duplicate of the target for the full version. Just right click on the full target, and select duplicate.
- Rename new target to something else (Flower Garden Lite–I’m highly imaginative when it comes to naming things like this!
- Make a duplicate of your Info.plist (InfoLite.plist)
- Change the info.plist file setting for the lite target to point to InfoLite.plist
- Edit InfoLite.plist to have a different bundle identifier and maybe a different bundle display name (the name that’s going to show up under the icon on the iPhone).
- Add a compiler define to the lite target called LITE or something like that. That way you can #ifdef a few parts of the code depending on the version you’re compiling.
And that’s almost it. There’s one more trick that made my life a lot easier. It turns out that you will definitely want to change not just some code, but some assets depending on which version you’re using. So maybe you’ll have a Wall.png texture in the full version, but you’ll want to have a different version of that texture in the Lite version. I started out creating a new file called WallLite.png, but then it quickly cascaded into a bunch of code changes loading either Wall.png or WallLite.png depending on the version and it was ugly and time consuming.
A much better approach is to rely on the resource copy step of XCode. By default, XCode will grab the resources in your project and copy them all in the same folder, flattening the hierarchy completely. This can be a pain if you have resources with the same name organized in different folders because they will clash. But here we can use it to our advantage to supply different versions of the resource for the full and lite versions.
Just create a Lite directory and put any variations of your resources there. Then, in the Resources Copy step of the target, remove the resources you’re replacing and add the ones from the Lite directory. Whenever you build, XCode will put those new resources in the same place where the full resources were and your code won’t have to change one bit. This trick works even with xib files, which is great because I had to modify one of them to reduce the number of pots in the garden screen.
Once you have that set up, the rest is just a matter of deciding what functionality goes in the lite version and how it is presented. It can be as simple or as complex as you want.
In the case of Flower Garden, it was very straightforward. I limited the number of pots to two, and the number of different seeds to three. So I just had to change a few resources and add a couple of #ifdefs with the number of total pots and seeds. I also removed the resources that weren’t used in the lite version (the seed data for all the unavailable seeds for example).
Flower Garden lite was finally approved and it has been available on the App Store for a few days. So far it has been downloaded several thousand times, it has been very well received, and has definitely bumped up the sales of the full version. Definitely a few hours well spent!
[1] The lite version took a couple of hours to create and a month to approve by Apple.
[2] It was something I wanted to have created from the beginning, but my hands were tied because email bouquets were being sent through my server and I had a maximum number of emails I was allowed to send per day because of spam limits. Fortunately, as soon as the 3.0 OS was released, apps were able to use in-app email and that restriction went away.
Pingback: Tweets that mention Games from Within | From Full to Lite in Under An Hour -- Topsy.com