Paying Off: The Story Behind Unearthed

Today I have the pleasure to introduce the first-ever guest post in Games From Within, Joey Chang. Like me, Joey worked for many years in the game industry, and finally took the plunge last October to become an independent game developer. Unearthed is his first iPhone project and it’s a very unique free to play, augmented reality (AR) game with an X-Files-like theme.

Joey was kind enough to share the story behind Unearthed, some of the decisions leading up to the final game, and the initial reception and sales numbers. Thanks Joey!

Inspiration

Nine months ago, without warning, a gnome crept into my head. It was an idea inspired from a friend’s chance mention of an activity called geocaching, where participants use a GPS to hide and seek containers across the world. Within hours, I had envisioned a global cross between geocaching, the Amazing Race, and online travel agency representatives. The idea didn’t look much like the resultant product nine months later, but it formed the most critical ingredient to any venture: the obsession to see it completed.

I spent my evenings for a few short weeks hammering out a design, scoping and cutting features, and beginning a prototype, but it didn’t take long for me to admit to the unavoidable truth that such a project would take months working full time or probably 3 to 4 times as many months working nights and weekends. I had to sit and carefully consider the pros and cons of leaving my job to pursue something I desperately wanted to create.

Half-Hearted Dissent

UnearthedPoster.jpgFor two weeks, I debated with my wife and close friends with startup experience. I drafted a list of pros and cons to quitting my job to pursue an iphone project and stared at it for hours. Those of you who have made the leap or considered it may recognize some of the points or have more of your own to add:

Advantages of quitting to work full time on an iphone idea

  • Focus effort, complete project 3-4 times faster
  • Gain valuable unique experience of running solo
  • Avoid coding burnout, alienating loved ones, loss of sanity
  • Resume padding

Advantages of keeping day job while working on iphone idea

  • Steady income in a scary economy
  • Not having to job search in a scary economy
  • Peace of mind (in a scary economy)

You can see where a large portion of the dissenting argument forms its basis. After two weeks of listening to unanimous encouragement (bordering on persistent nagging) to quit my job, two weeks of trying my best to convince myself why I should not quit my job, I did what my gut knew from day one was going to be best for me. I marched to my boss’s room and quit my job. Ok, I had maybe two false starts where I turned around and went back to my seat.

The Project Unearthed

Over the next 8 months, scoping and an inclination to appeal to a casual segment evolved the project into a global paranormal investigation titled Unearthed. I tried my best to figure how to maximize the success of the product, and compiled a list of all the ways I could imagine increasing the product’s exposure:

  • Banner ads
  • Spamming blogs and websites to review my product
  • Spamming friends on facebook
  • Writing a blog
  • Viral app features

I had trouble justifying the cost to pay for banner ads, and I had too much urgency to implement the product to devote time to a blog, so I focused on occasionally talking about the app on facebook, compiling a list of potential blog candidates for the day the app released, and devising viral features.

Screen1.jpgApart from typical facebook posting and email-a-friend features, I decided to employ a “refer-an-agent” feature which would enable users to invite others to join their network, essentially a grouping of users that correlated with how effectively their app could process scanned creature data. The larger the network, the more credit users would receive for uploading data, and the better they would perform in leaderboards and achievements. The approach was an “everybody wins” style where anytime any user in the network gained a referral, every single person in the network would benefit from the growth of the network. The hope was that this feature would gain a viral quality.

Friends placed immense pressure to release the product as soon as humanly possible under the theory that doing so would reveal the 70% of my design that was wrong, so I divided Unearthed into three releases. The app itself has three game modes, each incrementally accessible as a given region “levels up” from users’ data uploads. I would have time to release the latter modes while the first mode of the game, the most casual mode where users look around where they stand and scan for anomalies, was being played.

In App Purchases and Ads

Screen0.jpgConsidering the App Store was flooded with free apps and that I had no name in the industry to immediately convince users to immediately pay for my app, I concluded that the most likely approach for success was to release a free app with In App Purchases. This appeared to be the best way to get as many users to at least try the app and decide how much they wanted to spend to access more functionality. Initially, I offered the following items:

  • All content, present and future ($5.99)
  • Scanner upgrades level 2-3 ($1.99)
  • Scanner upgrades level 4-5 ($1.99)
  • Bounty Mode (coming soon) ($1.99)
  • Blitz Mode (coming soon) ($1.99)

However, I hit a snag with Apple’s terms which did not permit me to even mention any features that were not yet implemented. The first item was intended to be a bulk pricing investment in the forthcoming completion of the app, and the ‘coming soon’ items were just client-side displays to tease of the future modes (not actually registered products in the IAP servers). Because I had to remove them, I revised my IAP content to the following:

  • Scanner upgrades level 2 ($.99)
  • Scanner upgrades level 3 ($.99)
  • Scanner upgrades level 4 ($.99)
  • Scanner upgrades level 5 ($.99)
  • Scanner upgrades 2-5 ($2.99)

The app essentially gives users access to all features of the game, but with a lowly basic scanner that doesn’t boast the speed, range, and creature clearance levels of a fully boosted scanner.

I added Greystripe’s ad system as a means to offset the cost I might incur from using Google App Engine as my server solution. Considering the large amount of rank tracking required by my app, I estimated the revenue from ads to break even with the cost of using App Engine.

Release and Reception

The app was approved in the early afternoon of June 21st, a Monday. Excited, I quickly moved up the release date and it hit the stores later that afternoon. One week later, the sales are dismal, with about 400 total downloads and only a handful of purchases.

UnearthedWeek1.jpg

I considered possible contributors to this could be the following (in order of impact):

  • Requiring 3GS
  • Releasing 4 days before the iPhone 4 (dropping off New Releases)
  • Requiring OS 3.1.3 (instead of 3.1)
  • Releasing the app in the late afternoon (dropping off New Releases faster)

Without knowing the specifics on the sales of the 3GS versus the 3G and the iPod Touch, the fraction of 3GS users able to even see my app in the store might be a small fraction. Unnecessarily releasing under an OS that prevented users from installing unless they went back to iTunes to update their OS was likely a dealbreaker for browsing users (quickly remedied but days later). And considering how many of the 1.5 million users would be browsing the App Store for free apps Thursday, releasing a few days too early may have been the biggest avoidable mistake yet.

Moving Forward

As uninspiring as it was getting only a few hundred downloads and enough revenue for lunch, I had heard that word of mouth was a powerful vehicle, possibly the best vehicle, for an unknown developer, so my plan is to continue giving it more time and implement the GPS-enabled Bounty Mode which will take considerably less time, possibly a short 1-2 months. One week is certainly not a large enough measure of success, and already I’ve received a few responses from blogs willing to write reviews, so I’m hopeful of seeing the userbase grow and eagerly anticipating the next big server issue. In the coming weeks, there will definitely be no “sitting back while the cash rolls in”, as I recently had the blessing/curse of another inspiring must-create iPad app revelation and am sweating bullets designing and scoping while scheduling in work on Unearthed, all the while keeping a grave eye on the lifeline of my business.

Looking back at the struggling decision I made to quit my job, I’m reminded of some advice that was given to me beforehand. “Quitting your job will be the hardest decision, but it will make you feel great.” And like an enormous burden lifted from me, it did. And to this day, with earned lunch money in hand, it continues to.

Managing Data Relationships

I’ve been meaning to put up the rest of the Inner Product columns I wrote for Game Developer Magazine, but I wasn’t finding the time. With all the recent discussion on data-oriented design, I figured it was time to dust some of them off.

This was one of the first columns I wrote. At first glance it might seem a completely introductory topic, not worth spending that much time on it. After all, all experience programmers know about pointers and indices, right? True, but I don’t think all programmers really take the time to think about the advantages and disadvantages of each approach, and how it affects architecture decisions, data organization, and memory traversal.

It should provide a good background for this coming Thursday’s #iDevBlogADay post on how to deal with heterogeneous objects in a data-oriented way.

From a 10,000-Foot view, all video games are just a sequence of bytes. Those bytes can be divided into code and data. Code is executed by the hardware and it performs operations on the data. This code is generated by the compiler and linker from the source code in our favorite computer language. Data is just about everything else. [1]

As programmers, we’re obsessed with code: beautiful algorithms, clean logic, and efficient execution. We spend most of our time thinking about it and make most decisions based on a code-centric view of the game.

Modern hardware architectures have turned things around. A data-centric approach can make much better use of hardware resources, and can produce code that is much simpler to implement, easier to test, and easier to understand. In the next few months, we’ll be looking at different aspects of game data and how everything affects the game. This month we start by looking at how to manage data relationships.

Data Relationships

Data is everything that is not code: meshes and textures, animations and skeletons, game entities and pathfinding networks, sounds and text, cut scene descriptions and dialog trees. Our lives would be made simpler if data simply lived in memory, each bit totally isolated from the rest, but that’s not the case. In a game, just about all the data is intertwined in some way. A model refers to the meshes it contains, a character needs to know about its skeleton and its animations, and a special effect points to textures and sounds.

How are those relationships between different parts of data described? There are many approaches we can use, each with its own set of advantages and drawbacks. There isn’t a one-size-fits-all solution. What’s important is choosing the right tool for the job.

Pointing The Way

In C++, regular pointers (as opposed to “smart pointers” which we’ll discuss later on) are the easiest and most straightforward way to refer to other data. Following a pointer is a very fast operation, and pointers are strongly typed, so it’s always clear what type of data they’re pointing to.

However, they have their share of shortcomings. The biggest drawback is that a pointer is just the memory address where the data happens to be located. We often have no control over that location, so pointer values usually change from run to run. This means if we attempt to save a game checkpoint which contains a pointer to other parts of the data, the pointer value will be incorrect when we restore it.

Pointers represent a many-to-one relationship. You can only follow a pointer one way, and it is possible to have many pointers pointing to the same piece of data (for example, many models pointing to the same texture). All of this means that it is not easy to relocate a piece of data that is referred to by pointers. Unless we do some extra bookkeeping, we have no way of knowing what pointers are pointing to the data we want to relocate. And if we move or delete that data, all those pointers won’t just be invalid, they’ll be dangling pointers. They will point to a place in memory that contains something else, but the program will still think it has the original data in it, causing horrible bugs that are no fun to debug.

One last drawback of pointers is that even though they’re easy to use, somewhere, somehow, they need to be set. Because the actual memory location addresses change from run to run, they can’t be computed offline as part of the data build. So we need to have some extra step in the runtime to set the pointers after loading the data so the code can use them. This is usually done either by explicit creation and linking of objects at runtime, by using other methods of identifying data, such as resource UIDs created from hashes, or through pointer fixup tables converting data offsets into real memory addresses. All of it adds some work and complexity to using pointers.

Given those characteristics, pointers are a good fit to model relationships to data that is never deleted or relocated, from data that does not need to be serialized. For example, a character loaded from disk can safely contain pointers to its meshes, skeletons, and animations if we know we’re never going to be moving them around.

Indexing

One way to get around the limitation of not being able to save and restore pointer values is to use offsets into a block of data. The problem with plain offsets is that the memory location pointed to by the offset then needs to be cast to the correct data type, which is cumbersome and prone to error.

The more common approach is to use indices into an array of data. Indices, in addition to being safe to save and restore, have the same advantage as pointers in that they’re very fast, with no extra indirections or possible cache misses.

Unfortunately, they still suffer from the same problem as pointers of being strictly a many-to-one relationship and making it difficult to relocate or delete the data pointed to by the index. Additionally, arrays can only be used to store data of the same type (or different types but of the same size with some extra trickery on our part), which might be too restrictive for some uses.

A good use of indices into an array are particle system descriptions. The game can create instances of particle systems by referring to their description by index into that array. On the other hand, the particle system instances themselves would not be a good candidate to refer to with indices because their lifetimes vary considerably and they will be constantly created and destroyed.

It’s tempting to try and extend this approach to holding pointers in the array instead of the actual data values. That way, we would be able to deal with different types of data. Unfortunately, storing pointers means that we have to go through an extra indirection to reach our data, which incurs a small performance hit. Although this performance hit is something that we’re going to have to live with for any system that allows us to relocate data, the important thing is to keep the performance hit as small as possible.

An even bigger problem is that, if the data is truly heterogeneous, we still need to cast it to the correct type before we use it. Unless all data referred to by the pointers inherits from a common base class that we can use to query for its derived type, we have no easy way to find out what type the data really is.
On the positive side, now that we’ve added an indirection (index to pointer, pointer to data), we could relocate the data, update the pointer in the array, and all the indices would still be valid. We could even delete the data and null the pointer out to indicate it is gone. Unfortunately, what we can’t do is reuse a slot in the array since we don’t know if there’s any data out there using that particular index still referring to the old data.

Because of these drawbacks, indices into an array of pointers is usually not an effective way to keep references to data. It’s usually better to stick with indices into an array of data, or extend the idea a bit further into a handle system, which is much safer and more versatile.

Handle-Ing The Problem

Handles are small units of data (32 bits typically) that uniquely identify some other part of data. Unlike pointers, however, handles can be safely serialized and remain valid after they’re restored. They also have the advantages of being updatable to refer to data that has been relocated or deleted, and can be implemented with minimal performance overhead.

The handle is used as a key into a handle manager, which associates handles with their data. The simplest possible implementation of a handle manager is a list of handle-pointer pairs and every lookup simply traverses the list looking for the handle. This would work but it’s clearly very inefficient. Even sorting the handles and doing a binary search is slow and we can do much better than that.

Here’s an efficient implementation of a handle manager (released under the usual MIT license, so go to town with it). The handle manager is implemented as an array of pointers, and handles are indices into that array. However, to get around the drawbacks of plain indices, handles are enhanced in a couple of ways.

In order to make handles more useful than pointers, we’re going to use up different bits for different purposes. We have a full 32 bits to play with, so this is how we’re going to carve them out:

Handle.png

  • The index field. These bits will make up the actual index into the handle manager, so going from a handle to the pointer is a very fast operation. We should make this field as large as we need to, depending on how many handles we plan on having active at once. 14 bits give us over 16,000 handles, which seems plenty for most applications. But if you really need more, you can always use up a couple more bits and get up to 65,000 handles.
  • The counter field. This is the key to making this type of handle implementation work. We want to make sure we can delete handles and reuse their indices when we need to. But if some part of the game is holding on to a handle that gets deleted—and eventually that slot gets reused with a new handle—how can we detect that the old handle is invalid? The counter field is the answer. This field contains a number that goes up every time the index slot is reused. Whenever the handle manager tries to convert a handle into a pointer, it first checks that the counter field matches with the stored entry. Otherwise, it knows the handle is expired and returns null.
  • The type field. This field indicates what type of data the pointer is pointing to. There are usually not that many different data types in the same handle manager, so 6–8 bits are usually enough. If you’re storing homogeneous data, or all your data inherits from a common base class, then you might not need a type field at all.
struct Handle
{
    Handle() : m_index(0), m_counter(0), m_type(0)
    {}

    Handle(uint32 index, uint32 counter, uint32 type)
        : m_index(index), m_counter(counter), m_type(type)
    {}

    inline operator uint32() const;
    
    uint32 m_index : 12;
    uint32 m_counter : 15;
    uint32 m_type : 5;
};

Handle::operator uint32() const
{
    return m_type << 27 | m_counter << 12 | m_index;
}

The workings of the handle manager itself are pretty simple. It contains an array of HandleEntry types, and each HandleEntry has a pointer to the data and a few other bookkeeping fields: freelist indices for efficient addition to the array, the counter field corresponding to each entry, and some flags indicating whether an entry is in use or it’s the end of the freelist.

struct HandleEntry
{
	HandleEntry();
	explicit HandleEntry(uint32 nextFreeIndex);
	
	uint32 m_nextFreeIndex : 12;
	uint32 m_counter : 15;
	uint32 m_active : 1;
	uint32 m_endOfList : 1;
	void* m_entry;
};

Accessing data from a handle is just a matter of getting the index from the handle, verifying that the counters in the handle and the handle manager entry are the same, and accessing the pointer. Just one level of indirection and very fast performance.

We can also easily relocate or invalidate existing handles just by updating the entry in the handle manager to point to a new location or to flag it as removed.

Handles are the perfect reference to data that can change locations or even be removed, from data that needs to be serialized. Game entities are usually very dynamic, and are created and destroyed frequently (such as enemies spawning and being destroyed, or projectiles). So any references to game entities would be a good fit for handles, especially if this reference is held from another game entity and its state needs to be saved and restored. Examples of these types of relationships are the object a player is currently holding, or the target an enemy AI has locked onto.

Getting Smarter

The term smart pointers encompasses many different classes that give pointer-like syntax to reference data, but offer some extra features on top of “raw” pointers.

A common type of smart pointer deals with object lifetime. Smart pointers keep track of how many references there are to a particular piece of data, and free it when nobody is using it. For the runtime of games, I prefer to have very explicit object lifetime management, so I’m not a big fan of this kind of pointers. They can be of great help in development for tools written in C++ though.

Another kind of smart pointers insert an indirection between the data holding the pointer and the data being pointed. This allows data to be relocated, like we could do with handles. However, implementations of these pointers are often non- serializable, so they can be quite limiting.

If you consider using smart pointers from some of the popular libraries (STL, Boost) in your game, you should be very careful about the impact they can have on your build times. Including a single header file from one of those libraries will often pull in numerous other header files. Additionally, smart pointers are often templated, so the compiler will do some extra work generating code for each data type you instantiated templates on. All in all, templated smart pointers can have a significant impact in build times unless they are managed very carefully.

It’s possible to implement a smart pointer that wraps handles, provides a syntax like a regular pointer, and it still consists of a handle underneath, which can be serialized without any problem. But is the extra complexity of that layer worth the syntax benefits it provides? It will depend on your team and what you’re used to, but it’s always an option if the team is more comfortable dealing with pointers instead of handles.

Conclusion

There are many different approaches to expressing data relationships. It’s important to remember that different data types are better suited to some approaches than others. Pick the right method for your data and make sure it’s clear which one you’re using.

In the next few months, we’ll continue talking about data, and maybe even convince you that putting some love into your data can pay off big time with your code and the game as a whole.

This article was originally printed in the September 2008 issue of Game Developer.

[1] I'm not too happy about the strong distinction I was making between code and data. Really, data is any byte in memory, and that includes code. Most of the time programs are going to be managing references to non-code data, but sometimes to other code as well: function pointers, compiled shaders, compiled scripts, etc. So just ignore that distinction and think of data in a more generic way.

The Always-Evolving Coding Style

This is my first entry into #iDevBlogADay. It all started very innocently with a suggestion from Miguel, but the ball got rolling pretty quickly. The idea is to have one independent iPhone game developer write a blog entry each day of the week. At first we thought we would be hard-pressed to get 7 developers, but it’s starting to seem we might have multiples per day!

Check out the new sidebar with all the #iDevBlogADay blogs. We’re also putting together a common RSS feed if you want to subscribe to that instead.

Writing is addictive, so don’t be surprised if this once-a-week minimum turns into multiple-times-a-week.

 

matrix.jpgEvery developer who’s been working on a team for a while is able to tell the author of a piece of code just by looking at it. Sometimes it’s even fun to do a forensic investigation and figure out not just the original author, but who else modified the source code afterwards.

What I find interesting is that I can do the same thing with my own code… as it changes over time. Every new language I learn, every book I read, every bit of code I see, every open-source project I browse, every pair-programming session, every conversation with a fellow developer leaves a mark behind. It slightly changes how I think of things, and realigns my values and priorities as a programmer. And those new values translate into different ways to write code, different architectures, and different coding styles.

It never happens overnight. I can’t recall a single case where I changed my values in a short period of time, causing dramatic changes to my coding style. Instead, it’s the accumulation of lots of little changes here and there that slowly shifts things around. It’s like the movement of the Earth’s magnetic pole: very slow, but changes radically over time (although maybe just a tad bit faster).

Why Talk About Coding Styles

Coding style in itself is purely a personal thing, and therefore, very uninteresting to talk about. However, in its current form, my coding style goes against the grain of most general modern “good practices”. A few weeks ago I released some sample source code and it caused a bit of a stir because it was so unconventional. That’s when I realized it might be worth talking about it after all (along with George bugging me about it), and especially the reasons why it is the way it is.

Before I even start, I want to stress that I’m not advocating this approach for everybody, and I’m certainly not saying it’s the perfect way to go. I know that in a couple of years from now, I’ll look back at the code I’m writing today and it will feel quaint and obsolete, just like the code I wrote during Power of Two Games looks today. All I’m saying is that this is the style that fits me best today.

Motivation

This is my current situation which shapes my thinking and coding style:

  • All my code is written in C and C++ (except for a bit of ObjC and assembly).
  • It’s all for real-time games on iPhone, PCs, or modern consoles, so performance and resource management are very important.
  • I always try to write important code through Test-Driven Development.
  • I’m the only programmer (and only designer).
  • Build times in my codebase are very fast.

And above all, I love simplicity. I try to achieve simplicity by considering every bit of code and thinking whether it’s absolutely necessary. I get rid of anything that’s not essential, or that’s not benefitting the project by at least two or three times as much as it’s complicating it.

How I Write Today

So, what does my code look like these days? Something like this (this is taken from a prototype I wrote with Miguel of Mystery Coconut fame):

namespace DiverMode
{
    enum Enum
    {
        Normal,
        Shocked,
        Inmune,
    };
}

struct DiverState
{
    DiverState()
        : mode(DiverMode::Normal)
        , pos(0,0)
        , dir(0)
        , o2(1)
        , boostTime(0)
        , timeLeftInShock(0)
        , timeLeftImmune(0)
    {}

    DiverMode::Enum mode;
    Vec2 pos;
    float dir;
    float o2;

    float boostTime;
    float timeLeftInShock;
    float timeLeftImmune;
};

namespace DiverUtils
{
    void Update(float dt, const Vec2& tiltInput, GameState& state);
    void Shock(DiverState& diver);
    void StartSprint(DiverState& diver);
    void StopSprint(DiverState& diver);
}

The first thing that stands out is that I’m using a struct and putting related functions in a namespace. It may seem that’s just a convoluted way of writing a class with member functions, but there’s more to it than that.

By keeping the data in a struct instead of a class, I’m gaining several advantages:

  • I’m showing all the data there is and how big it is. Nothing is hidden.
  • I’m making it clear that it’s free of pointers and temporary variables.
  • I’m allowing this data to be placed anywhere in memory.

The fact that the functions are part of a namespace is not really defensible; it’s pure personal preference. It would have been no different than if I had prefixed them with DriverUtils_ or anything else, I just think it looks clearner. I do prefer the functions to be separate and not member functions though. It makes it easier to organize functions that work on multiple bits of data at once. Otherwise you’re stuck deciding whether to make them members of one structure or another. It also makes it easier to break up data structures into separate structures later on and minimize the amount of changes to the code.

Probably one of the biggest influences on me starting down this path was the famous article by Scott Meyers How Non Member Functions Improve Encapsulation. I remember being shocked the first time I read it (after having read religiously Effective C++ and More Effective C++). That reasoning combined with all the other changes over the years, eventually led to my current approach.

Since everything is in a structure and everything is public, there’s very little built-in defenses against misuse and screw-ups. That’s fine because that’s not a priority for me. Right now I’m the only programmer, and if I work with someone else, I expect them to have a similar level of experience than me. Some codebases written with a defensive programming approach have an amazing amount of code (and therefore complexity) dedicated to babysitting programmers. No thanks. I do make extensive use of asserts and unit tests to allow me to quickly make large refactorings though.

Another thing to note that might not be immediately obvious from the example above is that all functions are very simple and shallow. They take a set of input parameters, and maybe an output parameter or just a return value. They simply transform the input data into the output data, without making extensive calls to other functions in turn. That’s one of the basic approaches of data-oriented design.

Because everything is laid out in memory in a very simple and clear way, it means that serialization is a piece of cake. I can fwrite and fread data and have instant, free serialization (you only need to do some extra work if you change formats and try to support older ones). Not only that, but it’s great for saving the game state in memory and restoring it later (which I’m using heavily in my current project). All it takes is this line of code:

oldGameState = currentGameState

This style is a dream come true for Test-Driven Development (TDD). No more worrying about mocks, and test injections, or anything like that. Give the function some input data, and see what the output is. Done! That simple.

One final aspect of this code that might be surprising to some is how concrete it is. This is not some generic game entity that hold some generic components, with connections defined in XML and bound together through templates. It’s a dumb, POD Diver structure. Diver as in the guy going swimming underwater. This prototype had fish as well, and there was a Fish structure, and a large array of sequential, homogeneous Fish data. The main loop wasn’t generic at all either: It was a sequence of UpdateDivers(), UpdateFish(), etc. Rendering was done in the same, explicit way, making it extra simple to minimize render calls and state changes. When you work with a system like this, you never, ever want to go back to a generic one where you have very little idea about the order in which things get updated or rendered.

Beyond The Sample

To be fair, this sample code is very, very simple. The update function for a reasonable game element is probably larger than a few lines of code and will need to do a significant amount of work (check path nodes, cast rays, respond to collisions, etc). In that case, if it makes sense, the data contained in the structure can be split up. Or maybe the first update function generates some different output data that gets fed into later functions. For example, we can update all the different game entities, and as an output, get a list of ray cast operations they want to perform, do them all in a later step, and then feed the results back to the entities either later this frame or next frame if we don’t mind the added latency.

There’s also the question of code reuse. It’s very easy to reuse some low level functions, but what happens when you want to apply the same operation to a Diver and to a Fish? Since they’re not using inheritance, you can’t use polymorphism. I’ll cover that in a later blog post, but the quick preview is that you extract any common data that both structs have and work on that data in a homogeneous way.

 

What do you think of this approach? In which ways do you think it falls short, and in which ways do you like it better than your current style?

Increase Your App Ratings On The App Store

Every iPhone developer fears the one-star-on-uninstall rating. I understand Apple’s reasoning for adding the prompt for rating on uninstall, but since that’s the only time users are prompted, it becomes a very biased, negative rating. There may be hundreds of users happy with your app who never rate it on iTunes, but everybody who uninstalls it gets asked to give it a review. That’s quite unfair from the developer point of view.

First one bit of good news: That prompt-on-delete feature seems to be gone on iOS 4.0. That should make everybody happy. Even so, taking a pro-active position on this can only benefit developers.

Next a personal opinion without any real hard data to back it up: I don’t think App Store ratings matter very much. I see plenty of quality, 5-star apps that never go anywhere, as well as horrible apps with close to 1-star rating on the top 10. I’m sure good ratings help a bit, but not as much as some people may think.

One of the little features I snuck in the latest update of Flower Garden, was a prompt to rate (or re-rate) the app. This idea isn’t new, and I’ve seen quite a few apps doing it already. I think it makes a lot of sense and provides rating that is much more balanced and representative of how users feel about the app.

You have to be careful about how you prompt users though. This are the priorities I had in mind when I implemented the rating prompt in Flower Garden, roughly in order of importance:

  1. Don’t be annoying!
  2. Disrupt the user as little as possible
  3. Make rating the app as easy as possible.
  4. Prompt at every update.

fg_prompt.jpg

Don’t be annoying

This is by far the most important priority. If your prompt for review is annoying, you might get more angry users and one-star reviews than you would have without it. Be respectful of the user and don’t nag.

For quite a few versions, I’ve had a review button in the “Feedback” tab in the settings screen. Not many people use it or even know about it because it was several taps away from the normal flow of Flower Garden. That’s an example of a feedback prompt that is too unobtrusive. Clearly, I needed something a bit more noticeable.

What I did was to add an actual alert view with the prompt. That alert comes up very infrequently, and gives users the option to either rate it right away, be reminded later, or just stop asking altogether. Many more users rated the app through this mechanism (and I haven’t gotten a single complaint about it being annoyed yet–keeping my fingers crossed).

Disrupt the user as little as possible

First of all, you should never ask the user to rate the first time they launch it. They haven’t had a chance to check it out yet! Give them a few days (or a few launches of the app). That will benefit you in two ways: users will have a better chance to give an honest rating, and users who didn’t like your app probably won’t be around in two days, so they’ll never see the prompt.

Second, choose a good time to ask. Please, don’t ask me as soon as I launch the app! Chances are I want to do something with it, so being pestered with a review prompt is disruptive, especially because adding a rating involves leaving the app and going to iTunes. At the same time, don’t ask me in the middle of a level or when I’m engrossed in game. A good moment to ask for a rating would be after completing a level or two, or, in the case of Flower Garden, after sending a bouquet.

For extra bonus points, catch the user on a “good” moment. Maybe only ask them to rate the app if they actually beat the level. They’ll probably leave a better review than if they just lost and are in a bad mood.

The exception I made was if a certain amount of time went by and the user never got to the point of being prompted (some people just don’t send bouquets in Flower Garden). In that case, I will ask at startup or at some other, non-ideal point.

Make rating the app as easy as possible

This is the funnel principle at work. For every action the user has to do in order to leave a review, the fewer users will actually do it. It would be ideal if users could rate the app directly from the alert box. That would involve no extra actions (or leaving the app) and would result in the maximum number of ratings [1]. Unfortunately, that’s not the case, so we have to do the best we can with what we have.

So we want to minimize the amount of actions from the moment the user taps “Rate now” until they can enter the rating. We could send them to the product page on the App Store, but that would still involve them scrolling around, finding the rating button, tapping it, and entering the rating. We can do better than that: We can send them directly to the rating screen. Check out this great post for a dissection of iTunes links and how to create one to the review page. Make sure the technique you choose works on an iPhone (not all of them do!).

Prompt at every update

This one is easy: Just store the number of the last version the user wrote a review for, and if it changes, start from scratch again. That way you don’t have to write any custom code at every release. Also, make sure to respect the “Don’t ask anymore” option if the user selected that in a previous update.

Source code

Here’s the review request source code (released under the MIT license). It consists of only two standalone files, and all the review state is kept in the default, global settings. There are only three functions and it should be very self-explanatory:

	bool ShouldAskForReview();
	bool ShouldAskForReviewAtLaunch();
	void AskForReview();

The ShouldAskForReviewAtLaunch() function simply adds an extra condition of launching it X number of times before asking for review (this is in case the user never triggers the review condition).

Results

Does this prompt for ratings work? This is a screen grab from iTunes 5 days after Flower Garden 2.4 was released:

fg_itunes_ratings.png

A few interesting observations:

  • Ratings are higher than they were before. Before the free day, Flower Garden had an average of 3.5 to 4 stars.
  • Reviews are often shorter and less useful than unprompted reviews. There are a lot of 5-star “I love this app!” reviews without much more substance. (I’m not complaining, really).
  • Still a huge number of users chose not to leave a review. There are only 148 ratings, but there have been 30,000 upgrades to the latest version. A lot of people might have upgraded and not launched it, but even so, it’s a very small percentage.

Overall, it was a very small time investment and the results show it was definitely worth it. I’ll be using this approach in my future projects (unless future iOS versions take care of it automatically somehow).

[1] Apple, can we fix that? How about a REST API for leaving ratings and reviews? Pretty please?

Making A Living (Comfortably) On The App Store (aka The Numbers Post #2)

A few months ago, I wrote a post analyzing how Flower Garden had done since it was released. It was a story with lots of ups and downs, tales of trials and failure, but ending on a positive, optimistic note. It went on to become one of the most read posts in this blog, and the comments were all very encouraging. Clearly, people, and especially other developers, are hungry for this kind of data.

So here we go with the second part. How did Flower Garden fare after the new year? Was it just the Christmas purchasing frenzy that had a momentary effect on sales, or was there something more to it?

Recap and Overview

Here’s where we left off last time. The unusual part was how profits increased as soon as I added in-app purchases to Flower Garden in early December. It made for a very atypical sales plot.

Full

And here is how things look now. This plot includes the previous data so it’s easier to contrast before and after. The area in blue is the new data since the last post.

fg_total.png

Just glancing at that chart makes it clear that that the increase around Christmas wasn’t a fluke. It actually wasn’t even done going up. After all the spikes, and the weekly ups and downs, Flower Garden ended up settling to about $1,500/week. And that, even in California, I would consider it to be a comfortable living. What a different from the $50/day it was making last year!

So what exactly happened there? Let’s look at the new data in more detail.

fg_recent.png

At a glance, there are three, very different sections.

The Feature

The first one starts with a significant increase in sales (A), and is in large part due to being featured on the App Store worldwide as a Staff Favorite. It’s a nice spike, but it’s nothing like the x10 spikes other developers have seen with App Store features. That’s because the Staff Favorite slot, even though it’s a very prestigious one, it does not appear on the iPhone, only on iTunes. I do all my browsing and shopping through iTunes, but apparently I’m in the minority, so the effect on sales is greatly reduced.

That spike is also in part due to my last “numbers post”, which happened right at the same time (not completely accidentally). The page attracted about 15,000 views in a few days, so I’m sure a few of them translated in people checking out Flower Garden out of curiosity.

Valentine’s Day

The second spike isn’t hard to guess: It’s the weekend of February 14th, Valentine’s Day. The more things happen at once and the more something is in the public eye, the more of an impact it has. PR people have known that for a long time, and it was really brought home for me back in December.

Fortunately, I managed to make quite a few things happen in the days leading to Valentine’s Day weekend:

  • I released an update with couple new in-app purchases: A new set of seeds (Seeds of Love), and a greenhouse garden, for $0.99 each.
  • I sent out a newsletter to the 25,000 subscribers to the mailing list announcing the new items.
  • I put Flower Garden on sale for $0.99 (down from the regular price of $2.99).
  • Several web sites, including TouchArcade, covered the sale and the new update, giving it lots of visibility.
  • Flower Garden Free was the free app for February 14th on the Valentine’s Day Calendar.

All of that combined to cause the big spike in profits (B). You really need to look at the first plot to put it in perspective. Two days in around Valentine’s Day had higher profit than the initial release spike back in April of last year!

Winding Down

Of course, everything that goes up, must eventually come down. So the weeks following Valentine’s Day profits went rapidly down. It was at the very end of April that I started working on Lorax Garden, so for that period of time I wasn’t able to do anything related to Flower Garden. For a while sales were dropping quite rapidly, but they eventually flattened out to about $1,500/week (C).

The good thing about having consumable items as in-app purchases (fertilizer in this case), is that profits are related to active user base, not just initial sales. So even though the amount of downloads decreased significantly during this time, the user base had grown a large amount, and with it, the daily profits.

Flower Garden Free

Back in December, there seemed to be a connection between the amount of downloads of the free version of Flower Garden and profits. They both picked up right around the time I added in-app purchases, although I was never able to tell if it was cause or consequence.

This is the amount of downloads of the free version for this period of time.

fg_free.png

It stays pretty regularly at about 800 downloads per day (which is not much compared to a lot of free versions out there), and has a massive spike on Valentine’s Day (caused by word of mouth, lots of sent bouquets, and the Valentine’s Day Calendar).

Notice that the App Store feature for Flower Garden (full version) in January had virtually no effect on downloads of the free version. It seems that people are willing to buy something full price without trying the free version first if Apple features it.

Both versions of Flower Garden (free and full) have in-app purchases in them. Even though there’s a higher percentage of users with the full version that buy in-app purchases, the free version is much more popular and the majority of the revenue comes from the free version (orange). This is a tren that was already noticable around the holidays, but now is much more clear, with over 50% of the revenue coming from in-app purchases in the free version.

iap_profit.png

The Future

The data for this post stops at May 5th. That’s because on May 6th I released a new set of seeds and gave Flower Garden away for free as part of the Mother’s Day promotion. As soon as the dust settles from that, I’ll write a third post detailing how it turned out.