It’s hard to find the right words to describe the launch of KoboldTouch. I can’t think of anything else but WOW! right now. :)

I can’t wait to hear what you have to say about KoboldTouch, and then act on your feedback.

For those who were just waiting for the launch:

Sign up on the KoboldTouch product page to get access to KoboldTouch and Essential Cocos2D.

The rest of this post is a summary of what I wrote before on these two-products-in-one. Actually, I think of KoboldTouch & Essential Cocos2D as being much more a service than products. And it’s a full time commitment from myself.

This calls for music! :)

Continue reading »

Tagged with:  

The Ultimate Cocos2D Project: Startup

On March 12, 2011, in Kobold2D, by Steffen Itterheim

The Ultimate Cocos2D Project is: Kobold2D!

Put simply: Kobold2D is designed to make Cocos2D developers more productive.

Original Post

Time for a weekly update. This time about startup code and configuration. One of the things that I frequently encountered following the development of Cocos2D and working with it, is how any change to the startup code - the main function, the App delegate and the root ViewController - caused issues and headscratching among developers.

I decided it doesn’t need to be this way.

The main() function

A code snippets speaks more than words:

[cc lang=”ObjC”]
int main(int argc, char *argv[])
{
return KKMain(argc, argv, NULL);
}
[/cc]

That’s right, all of the startup code is now part of the project’s source code. You can still do whatever you need to do before and after the call to KKMain (probably nothing, except maybe anti-piracy code). And the third parameter (NULL) to KKMain is reserved for future use, to pass in any configuration parameters if the need arises.

Let’s see what KKMain does:

[cc lang=”ObjC” height=”650″]
int KKMain(int argc, char* argv[], SMainParameters* userParameters)
{
SMainParameters parameters;
initMainParameters(&parameters, userParameters);

#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
#else
// Mac OS X specific startup code
[MacGLView load_];
#endif

// This makes the CCDirector class known to wax:
[CCDirector class];
// wax setup is sufficient for all intents and purposes
wax_setup();

[KKLua doString:kLuaInitScript];
[KKLua doString:kLuaInitScriptPlatformSpecific];
[KKLua doString:kLuaInitScriptForWax];

// This loads the config.lua file
[KKConfig loadConfigLua];

// run the app with the provided general-purpose AppDelegate which handles a lot of tedious stuff for you
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
int retVal = UIApplicationMain(argc, argv, nil, parameters.appDelegateClassName);
[pool release];
#else
int retVal = NSApplicationMain(argc, (const char**)argv);
#endif

return retVal;
}
[/cc]

The usual, really, except that it also initializes Wax and thus Lua for your App as well as providing the necessary startup code for both supported platforms: iOS and Mac OS X. The KKLua class is an Objective-C wrapper around the most imortant Lua functions, most notably it has the doString and doFile methods which allow you to run any Lua code or file containing Lua code.

KKConfig is a class that loads a Lua table and stores it in a NSDictionary for fast access to Lua parameters at runtime. I’ll discuss it in detail another time. The main purpose of KKConfig is to loadConfigLua, which loads the config.lua script returning a table containing startup parameters and making those parameters available to Objective-C.

Config.lua in detail

Let’s have a quick look at an excerpt of the config.lua file. It contains all of the startup parameters a developer using Cocos2D would ever want to tweak in a conveniently editable Lua script:

[cc lang=”Lua” height=”400″]
local config =
{
KKStartupConfig =
{
— load first scene from a class with this name, or from a Lua script with this name with .lua appended
FirstSceneClassName = “GameScene”,

— set the director type, and the fallback in case the first isn’t available
DirectorType = DirectorType.DisplayLink,
DirectorTypeFallback = DirectorType.NSTimer,

MaxFrameRate = 60,
DisplayFPS = YES,
DisplayFPSInAdHocBuilds = NO,

— Render settings
DefaultTexturePixelFormat = TexturePixelFormat.RGB565,
GLViewColorFormat = GLViewColorFormat.RGB565,
GLViewDepthFormat = GLViewDepthFormat.DepthNone,
GLViewPreserveBackBuffer = NO,
GLViewMultiSampling = NO,
GLViewNumberOfSamples = 0,

Enable2DProjection = NO,
EnableRetinaDisplaySupport = YES,

— … and many more settings!
},
}

return config
[/cc]

Since you don’t want to guess what those settings mean, I’ve documented them for you:

Config.lua Parameter Documentation (PDF)

This should also illustrate the kind of documentation I’m striving for. Documentation will be available online. It’s created in a Confluence Wiki with the help of ScreenSteps for more visual, step-by-step documentation.

App Delegate & Root ViewController

You may be wondering how you can modify and tweak the App Delegate and Root ViewController if they’re both part of the distribution, rather than copied into each project? That’s actually very simple: both are regular Objective-C classes, so they can be subclassed and methods overridden as needed.

Both KKAppDelegate and KKRootViewController provide a default implementation which you can tweak with the config.lua parameters. If that shouldn’t be enough, for example if you have to plug in some 3rd party code into the App Delegate, each project will have a subclass of KKAppDelegate and KKRootViewController in which you can override any of the UIApplicationDelegate and UIViewController protocol methods. Usually you would first call the super implementation, unless you want to entirely replace the default behavior.

The KKAppDelegate method calls one specific method called initializationComplete at the end of the delegate method applicationDidFinishLaunching. This allows you to run any custom code right before the first scene is shown. You can use that to call the CCDirector runWithScene method manually, in case you have more than one scene which might be run as first scene depending on certain conditions.

If you set the FirstSceneClassName config.lua setting, the project will first check if there’s a classname.lua file. If so, it will run this Lua script, assuming it contains the implementation of the first scene (more on that some other time). Otherwise it checks if there’s an existing Objective-C class derived from CCScene with that name, and if so allocates and initializes this scene and calls runWithScene for you.

In essence

From your point of view, the execution of the App now starts with the first scene, before that there’s no code that you’ll have to concern yourself with. Any startup configuration tweaks that you need to do can be done comfortably via the config.lua file, and the only setting you’ll need to change is the name of the first scene’s class name or Lua script. In addition you’ll get access to some features out of the box, for example adding iAd banners is now a simple on/off switch.

Moreover, any time there’s a change in Cocos2D’s startup code, or the startup code in any other library (most notably Wax), I can just make those changes for you and release a new version. This isn’t something you need to concern yourself with anymore, and makes upgrading existing projects to new versions of Cocos2D and other libraries even easier.

Today it was exactly 6 months since I made the first sale of my Line-Drawing Game Starterkit for Cocos2D. I just glanced at the number labelled “Total” in the Plimus control panel: $18,479.05 … all of this from a single product over a period of 6 months!

No Product Launch Formula

I wish I could tell you exactly how to reproduce that level of success. I certainly did not implement the widely publicized and so called product launch formula. I’m sure PLF is valuable but the way it’s being sold makes it a scam to my mind. Why? Because it’s sold only once or twice a year, you can never just buy it, you have to wait for it, and when it goes on sale, people are more than happy to pay an outrageous price for something they could get much cheaper from reading the proper books and applying some common sense. That’s just a side note.

I also have to admit, I have no hard data where my customers are coming from other than they’re from all over the world. Or why each of them is buying or why some of them are interested but end up not doing it. Some will have followed me for quite a while, some found my website via google, others got wind of it through word of mouth and most recently they may have read about the Starterkit in my Learn Cocos2D book.

For the most part I have only informal data that I can share.

Little hard data

Thankful customers writing me that this was exactly what they’ve been looking for, and why. Only 3 refunds if I recall correctly, two were expecting something different and another one found Corona shortly after buying and decided to use Corona over Cocos2D, so he wasn’t going to use my Starterkit. As far as I can tell, most customers are not companies or teams of people but individual developers.

The level of support requests I received were minimal. I estimate that less than 10% of all customers contacted me for support, and almost all support incidents were solved after exchanging one or two emails. Most issues were caused by the fact that I didn’t include Cocos2D with the download, so they were mostly Cocos2D version mismatches and incorrect project setups. I definitely learned from that and will be including Cocos2D in all future versions of the Starterkit to cut down support incidents even more.

Clearly, there are two distinct groups of customers: those who would like to learn how to write a Line-Drawing game, hoping to eventually release it and in any case learn to understand Cocos2D and game development a little better on the side. And then those who plan to publish a commercial Line-Drawing game and want to cut corners, speed up development.

What I learned

For a while I was thinking that you need to have a frequently visited website like mine - over 5,000 visits per week here. You need to be well connected (followed) on Twitter. A Newsletter with many people on it that you can write to at any time is also very helpful. And having been a long time developer at Electronic Arts must surely be reassuring that I know what I’m doing. Next to actually showing that by writing a book. None of that is something you can do in just a couple of days or weeks.

I’m happy to report that you don’t need any of that to reproduce the success I’ve had with my Starterkit.

So skip your job application for EA, scrap the book draft and save your money on yet another type of scam: how to get 10,000 Twitter followers in 30 days. You don’t need them. Dan Nelson told me recently that the source code for his BATAK Duel game sold 14 copies in less than a month, priced at $297 (now: $149.99). The product page was just a simple blog post and yet still managed to bring in over $4,000 of revenue in the first month! For comparison, the first 30 days of the Line-Drawing Kit amounted to sales worth $5,370 revenue (before tax and everything).

BATAK Duel gameplay video:

I can also say with certainty that promo codes are a great idea, my 50% sale was a huge success. It generated over $4,000 in revenue and with another $5,000 made in the first month that means that half of my sales were generated by only two events: product launch, and 50% off promo codes. Maybe there’s something to the product launch formulas after all? But honestly, I think that’s just common sense. If you want to sell something, don’t sit around hoping for customers coming to you. Just as much as sex sells (in general), events sell products. Price drops, bundles, freebies, and so on. Get the word out, and do it frequently, and give something away for free - the simplest being information, knowledge, share experiences and data.

And think Steam!

I could have done more of that. But I was writing a book and it was also kind of an experiment to see how sales are affected if I’m not promoting the product in any way for a while. It was sobering to see sales drop to just a few per month three months after launch. Likewise it was exciting to see the reception (and sales) during the 50% sales event.

What I can also say with confidence is that if you offer a products that developers are interested in, they will buy it. And quite a number of developers are interested in commercial source code products to make this a viable market. It’s not just game code, it’s also components for regular App development that are very popular and lucrative.

The Secret is: Common Sense

And there’s another secret I’d like to share: developing an App Store game takes months to complete it, and if you’re truly passionate it can take even more months just to polish it, get it right in every aspect. Still your chances of tanking in the market are rather high, the stakes are high but the risks are even higher, even more so the longer you’ve spent developing your game.

So it’s only going to be a matter of time before more developers learn the secret that selling one’s source code for a game that’s already on the App Store is not just an additional revenue stream, it’s a rather lucrative one and one that allows you to cross-promote both products. In fact, suddenly you have two products on two different markets for two different kinds of customers with very little extra effort.

Don’t put all your eggs in one basket. Think about it. It makes perfect sense.

Even more so for me because I have always enjoyed working on game technology and enabling game developers to excel more than actually finishing a game, with polished gameplay, an intuitive user experience and fixing all those obscure bugs cropping up at the last minute.

Also, if you need help making sales, I have good news for you: there will be an affiliate store available here in the next couple weeks. If you’re interested in becoming an affiliate, give me a shout.

Tagged with: