CLM logo Development Blog by CLM

Remote tweaking

A long time ago in 2010, I have read an interesting article about Remote game editing by Noel Llopis, but it was just last year that we have implemented something similar and I must admit it makes a big difference during development. Basic concept is the same, although we’ve made some implementation choices that I think are really interesting.

First of all, our primary intent was to tweak global constants. Let’s say that there is something like this in the code:

namespace
{
	const float EnemyKillRadius = 36.0f;
}

It might take a few “edit-compile-run” cycles to find an optimal value for that variable and it takes that precious development time that could be better spent. To speed it up, we can register it in Tweak Server like that:

namespace
{
	WOMBAT_TS_FLOAT(EnemyKillRadius, 36.0f);
}

But hey, what this line of code actually does? Well it depends. In release builds it evaluates to simple constant variable, but in debug/test builds it’s a little more complicated:

#define WOMBAT_TS_FLOAT(name, value) WOMBAT_TS_FLOAT_INTERNAL(__FILE__, __LINE__, name, value)
#define WOMBAT_TS_FLOAT_INTERNAL(file, line, name, value) \
	float name = value; \
	static Wombat::TS_RegisterFloat WOMBAT_COMBINE(registerFloat, __LINE__)(file, line, #name, &name, value);
	
class TS_RegisterFloat
{
public:
	TS_RegisterFloat(const char* file, int line, const char* name, float* ptr, float value)
	{
		TweakServer::Instance()->RegisterFloat(file, line, name, ptr, value);
	}
};

TweakServer instance is created by the first Instance() call and it stores information about all registered variables (including variable name, source code file name, line number, pointer to the variable and initial value).

Communication between the server and a GUI client is handled with protobuf messages over network socket. When the Tweak Client is running, it looks like this:

remote-gui

One of the most important features is the magical Apply button — as each variable is registered with an additional information about the place in the source code, GUI tool can put the new value directly into the code, so it will be there during the next compilation.

First tab in the GUI tool allows us to pick files which should be included in the tweaking process. It helps to see only the things you are about to change and minimizes unnecessary scrolling.

Our Tweak Server / Client implementation allows us to use it with floats, ints, colors and also execute of simple actions. The next screen shows a little more real example of actions and variables:

remote-gui-2

There is still a lot that can be improved and added, but the current solution just works and we are very happy with it. It already saved us a lot of time and effort.

Transparency Optimization

During the implementation of a 60 FPS support we noticed that a few levels were not working as fast as they should. After digging a little deeper we found out that our bottleneck was the rendering.

In one of those cases, the texture we used looked like that:

What’s wrong with it? It’s 128×128 (16384 pixels), but it’s quite easy to notice that lots of pixels on the sides of it are transparent. After a few moments of trimming it down we got 108×108 texture that looks like this:

108×108=11664, so the new texture contains almost 29% less pixels It’s a quite good optimization! When a few dozens of sprites are rendered on the screen this might make a significant difference for your fillrate.

It’s important to remember that transparency comes at a cost, there is no way to discard transparent pixels prior to the texture fetch. Trimming down textures also helps to reduce size of the rendered sprites, which might lead to nice performance increase in GPUs that use tiled rendering (like the PowerVR GPUs used in Apple mobile devices).

iOS 6 adaptation

It has been just a few days since iOS 6 became available, but we think that information about it adaptation by users is interesting.

This chart shows OS version in Anodia sessions from the last week:

It’s easy to notice that most of the users have one of the two most recent OS versions, which is great from the developer perspective. What is more important, it looks that iOS 6 share is almost the same as iOS 5.1.1 share.

Stat tuned! We’re going to provide similar chart when the data from a few weeks will be available.

In-App Purchases piracy

Today I want to discuss one issue that we noticed after introducing Anodia 2.0 version — piracy of In-App Purchases.

For quite some time, we’ve been using Localytics to gather statistics that help us improving our games. One of them counts the number of coin purchases. To be honest, I never supposed that the number of pirated IAP might be so high — just check the graph for Coins Purchase event:

Coins Purchase event was reported almost 10000 times, that’s huge. But, you know what? In the same time we had 150 IAP sales, it means that in our case 98,5% Coins Purchases events are due to piracy. Not to mention that not all players are visible in Localytics (because we send the events only when a player is playing Anodia and is on a wifi).

We’re probably a little bit guilty here as we’re not doing any kind of receipt validation, but I’m personally shocked by the scale of this problem. It’s a little bit sad too, as that additional income from IAP would make a big difference in going indie full time. Unfortunately it’s still not possible.

If you’re interested in per-country details, here they are:

As you can see China is the biggest IAP consumer (even though it’s one of the few countries where Anodia has a 4.5 star rating instead of a 5). If you are curious how many of those real 150 IAP sales were made in China, here’s your answer: 1. The cheapest of course ;) .

We’ll probably introduce receipt validation sometime soon, but I believe that this should be a little bit more protected by the App Store itself.

I would also like to thank everyone who resisted the urge to pirate the IAP and supported us. Thank you, it really means a lot to us!

BTW, Anodia 2.1 is available and it runs in 60 fps on devices with Retina Display and on all iPads. It’s really nice and smooth, you should check it out.

Living in a 60 FPS world

When we released the first version of Anodia we received a few questions about frame rate in our games. To be honest, our target was to have solid 30 FPS on almost every possible device (unfortunately first and second gen devices tend to be a little slower). It seemed that achieving more FPS would be very complicated, especially as some parts of our framework were not prepared for this (i.e. using frames instead of time deltas).

As a first step we decided to check if it’s worth effort at all. We changed hard-coded FPS from 30 to 60 and I personally was shocked — game was running at double speed, but all menus were perfectly smooth! GUI is completely time based so it was possible to make comparison on two devices.

Our logic was already decoupled from rendering, but it was driven by the same TaskManager class. The tricky part is that TaskManager updates were handled by NSTimer with 1 ms interval. It was time to finally use CADisplayLink and trigger rendering from there. After fixing some bugs in TaskManager and implementation changes in Renderer we were able to get 60 FPS without changing game logic (still updated 30 times per second).

This is when the real fun begins — at this point everything looks the same as in 30 FPS, time to interpolate. Framework required adaptation in GUI, ParticleSystem, FadeIn/FadeOut transitions. Just take value from the previous and the current logic update and do linear interpolation to get value in between.

When framework was ready for 60 FPS, updates in Anodia started — after changing bonus manager (those falling down bonuses) and game objects handling most levels are working perfectly fine. There are only a few that require some manual tweaking. As we were aiming in 30 FPS in the beginning, sometimes performance is a bottleneck, but it seems that this should be not so difficult to fix.

What does this mean for players? Anodia and Hexbee updates are coming soon, including smooth 60 FPS on iPhone/iPod with Retina Display and all generations of iPad. Unfortunately we are not able to test it on iPhone 3GS so no promises for this device.

If you are interested in this topic, Noel posted an interesting article that made our quest to 60 FPS a lot easier.

Anodia 2.0 is ‘Waiting For Review’

A few days ago we shared an information on our Twitter and Facebook that Anodia 2.0 is ‘Waiting For Review’. Keep fingers crossed for a quick approval!

What does this mean for us? We should finally have more time to write regular entries on our devlog and start prototyping new games. And we sure have a lot of (potentially) neat ideas that we want to try! :)

The New iPad’s Retina Display

Since the Apple keynote about the new iPad I was wondering if the Retina Display is really going to be that big of a deal. I mean, I know it’s great on the iPhone 4 and the newest iPod touch, but those are the devices that you held a lot closer to you eyes so it makes a huge difference there. As it turns out, from the moment I turned the new iPad on, I knew the answer. Retina on the iPad is just great. But let me show you this on a little example from our game Hexbee which already fully support the new Retina display.

On the left you can see the little part of the screenshot taken on the old iPad, and on the right the new iPad. The difference is stunning. And with the new iPad Retina you can really see a whole new level of detail like on the following screenshot:

That donut looks really yummy! Below you can follow the evolution of the donut from the old iPhone and iPod touch without Retina (on the left) through iPad and Retina iPhone and iPod touch (center) to the new iPad (right):

The problem with perceiving the difference is that the new iPad and the old iPad have screens of the same size, but the old iPad have a lot less pixels there (not to mention, our screens have less pixels). For me, the best way to see that difference is to scale the old iPad screenshot up to the size of the new iPad. It really looks like the picture below (yet it’s not so big, obviously).

I hope that clarifies the importance of the new iPad Retina display — for me it’s most certainly is its killer feature.

Keeping things organized

We are busy with Anodia update, so just a short entry this time. I want to share a great tool from Fog Creek that we use daily — Trello.

Just take a few minutes to get familiar with it:

In our current setup we use one board per project (framework, Anodia, Hexbee). Each board is divided into four columns:

  • To Do — current task list
  • Ongoing — tasks that we are working on
  • Done — completed tasks, to be deleted after verification
  • Future — tasks to be done in distant future

This simple setup works like a charm and overhead from having everything written down is minimal.

BTW. From other news, iCloud synchronization for score, stars and unlocked levels is awesome ;)

Impact of FAAD campaign on Anodia

We recently shared information about strange situation with Anodia Lite downloads, this time we would like to share some information about impact of FAAD campaign on Anodia. Agreement with FAAD is negotiated individually by developer and we’re not able to say anything about it, but I hope that information in this post will be useful.

Anodia was included in FAAD at the end of August 2011 — Anodia was free from August 29th to September 6th. It’s a little bit more than one day, but that’s actually the point of making such campaigns — try to be free as long as the game is getting up / stays high in ranks. Total amount of downloads during the free period was about ~2.2 mln and we reached #1 in free apps in a couple of countries, including USA.

Sales after campaign are certainly bigger then before it, this is the profit chart from the first 6 months of Anodia sales:

There are two spikes, the first one is when Anodia appeared on the AppStore, the second one is just after FAAD campaign. It’s easy to note that profit after FAAD campaign stabilized at a higher level then before it. To be honest, it never went back to pre-campaign level so we’re actually happy with the campaign results.

Cooperation with FAAD was a good move and we’re glad that we’ve done it.

How we organize our projects

Today I want to share a little bit information about how our projects are organized from the technical side. As a foreword I should mention that 99% of our code is written in C/C++ and we’re using Objective-C only for communication with iOS.

One of our fundamental concepts is that we should share the most of the code between our projects instead of copying it. That’s the reason why we have a separate Framework project. Every one of our games or prototypes is using this Framework and during the development we’re trying to expand it with additional features. Currently it’s responsible for game states, memory, resources (Textures, sounds and audio streams), GUI, input, social features (leader boards, achievements) and simple data storage. When we think that some part of game code is reusable, we try to make it a part of the Framework.

Framework is also working as a layer between operating system and the game code, so there is almost no platform specific code in games. Currently we’re supporting iOS (iPhone, iPod Touch, iPad), OS X and Windows. System specific part of the Framework have API in C and this simplifies making it cross-platform.

Compilation of our Game for iOS looks like that:
1) compile Framework to framework.a
2) compile External Libraries to libraries.a
3) compile Game to game.a
4) copy .a files to Xcode project template that implements API, build and link it together

Xcode project may be customized by additional scripts to change project name, version, etc.

We store our projects in Git repositories. Whole building process is automated and we’re using Jenkins for continuous integration. We’re able to download latest builds from it with AdHoc distribution which is pretty great.

I think that this process works well for us and we’re going to expand it further in the future.

As a final note I just want to mention that our Framework is called Wombat ;)