Archive for the ‘Android’ Category

Sales and Ads Stats for Hashi Puzzles (iOS, Google Play and Amazon App Store)

Thursday, January 17th, 2013

Hashi Puzzles: Bridges & Islands is a mobile game that I released a few weeks ago on three mobile platforms: Google Play on November 25th, 2012, App Store (iPhone/iPad) on December 3rd and Amazon App Store on December 18th.
Here are a few statistics about the sales and ads revenue of the game.

The Game

Hashi Puzzles is a logic game (same kind of gameplay than sudoku). This game was an experiment on two specific points:

  • I wanted to develop a game very quickly. The initial version was made in 45 hours (read “How I Developed and Released a Game in 45 Hours“)
  • I wanted to allow players to spend more than $0.99 if they like the game. Therefore, the game is made up of level packs. Three packs of 20 levels each are available for free. Then, the player can buy up to six packs of 60 levels each for $1.99 per pack. This is considered expensive for a mobile game, even though I think that multiple hours of gameplay for the price of a cookie is still cheap, but that’s not the point here :) . I had a few reviews mentioning the price, as expected.

Let’s see some charts.

First stat: Downloads

On the charts the horizontal axis is the number of days since release on the given platorm.
downloads

As you can see, on iOS, the downloads are great after the release, probably because of the “New Releases” section. After that, the game was featured in the Puzzle and Family charts in France and USA. The game left the charts on December 31st, and you can see the final drop after day 28.
Downloads are now quite low for every platform (between 5 and 30 per day).

Second stat: Sales

As this is a game with in-apps, a single player can purchase multiple packs of levels. Each pack sold is considered a sale.
salesSince the game is released, I’ve had sales everyday on iOS. However, it took 14 and 12 days to get my first sale on Google Play and Amazon respectively!
Obviously, more downloads led to more sales. Let’s see the connection between downloads and sales in the next chart.

Third stat: Sales per Download

This chart shows the number of pack sold for 100 users. For instance, 2% means that on average for 100 downloads, I sell two packs (at $1.99 each). I don’t know if both packs are bought by the same player or different players (this information is only available on Google Play). The horizontal axis goes to 49 days in this one.
packs_per_dl It’s interesting to see that iOS is also much better compared to Android in this chart. Players spend more on iOS (this will not be a surprise to most of you). The value is also still increasing on iOS. I suppose that’s because players downloading the game recently probably searched for the game. They probably like it better that someone that downloaded it right after the release, just because it was new.

Fourth stat: sales per pack

sales_per_packThis stats shows that many players bought the last (hardest) pack without purchasing the previous ones. The most sold packs are the first one, second one and last one.

Fifth stat: Revenue repartition

Let’s see now the revenue repartition between sales, ads, iOS, Google Play and Amazon. Please note that ads revenue for Google Play and Amazon are shown together.
revenue_repartition
Blue is iOS, Red is Android. No surprise here, given the previous charts.
I use iAd and AdMob on iOS, and AdMob only on Android. I was disappointed by revenue on AdMob Android, especially compared to my previous game Don’t Feed the Trolls (sales stats). However it’s fair to notice that the TTR (Tap Through Ratio, amount of player taping on the ads) is 10 times lower on Hashi Puzzles compared to Don’t Feed the Trolls.

Sixth stat: total revenue per platform

net_revenue_per_platform
I made more than 12 times more money on iOS compared to Android. This is a surprise to me as once again, I had really different stats with my previous game. Overall, Hashi Puzzles was more successful than Don’t Feed the Trolls. It’s even more successful if we consider that:

  • I had no press converage for Hashi: this is a simple game, not very original that most journalist don’t care about
  • I spent much less time and money making the game

That’s it! Feel free to share and comment, or ask me anything on twitter @Frozax !

Building for Android with Cocos2d-X (NDK+JDK) in one step

Friday, October 5th, 2012

One Step to Better Code

Recently, I’ve read once again the old but awesome article “Joel Test : 12 steps to better code” (do it now if you haven’t). When developing Don’t Feed the Trolls, I always had a few steps to build a new android version of the game. I made a few scripts but I still had multiple steps. My workflow was:

  1. Copy the resources in the android assets folder
  2. Compile the C++ code with Gygwin
  3. Launch eclipse
  4. Use option Android / Build Signed Package in Eclipse
  5. Type two passwords for signature

I recently improved this workflow, and now it is:

  1. Double click the “build_android.bat” file

Much better!
Here are details of the script.

1. Copying the resources

It’s simple batch script that copies the resources from the multiplatform “Resource” folder (used in cocos2d-x templates) to the assets folder used on Android.

rmdir /S /Q "D:\gamedev\Games\swg21\Dev\android\assets"
mkdir "D:\gamedev\Games\swg21\Dev\android\assets"
xcopy "D:\gamedev\Games\swg21\Dev\Resource" "D:\gamedev\Games\swg21\Dev\android\assets" /S /H
del "D:\gamedev\Games\swg21\Dev\android\assets\snd\*.wav"

I first delete the existing files. Then I create the directory and copy all my resources. Finally, I remove wav files, as these are used only on the windows version. My multiplatform Resource folder contains sound in formats for all platforms.

2. Compiling the C++ source code

The native C++ code is compiled in cygwin. I spent a lot of time trying to figure out how to run a script from a batch and having it return immediately (with an error code). For the record, I was missing the –login parameter to the bash command. Here is the command I use:

cd "d:\gamedev\cygwin\bin"
bash --login "./swg21.sh"

The swg21.sh is a bash script placed in my home folder, calling cocos2d-x build_native script.

cd /cygdrive/d/gamedev/games/swg21/dev/android
./build_native.sh

build_native.sh is a bash script calling ndk-build after setting up proper environment variables.

3. Compiling the java and creating the signed apk

This was the main step I wanted to optimize from my previous workflow. Running Eclipse just to build a version was really slowing down the whole process. For that part, you have to use ant, as explained in the Google documentation.

cd "D:\gamedev\Games\swg21\Dev\android"
call ant release

The problem was that I was still asked to enter my password to sign the apk. This is fixed by editing the ant.properties file, as shown below (Credit goes to NickT from stackoverflow):

key.store.password=password
key.alias.password=password
key.store=path/to/your.keystore
key.alias=alias

4. Dropbox

I use dropbox to transfer apk to my Android device. Therefore, I need to copy the file to my dropbox folder.

copy "D:\gamedev\Games\swg21\Dev\android\bin\swg21-release.apk" "C:\Users\Win7\Dropbox\temp\swg21.apk"

5. Error checking

Steps 2 and 3 can fail (compile errors). I added some batch script to change the screen color to green when it’s successful, and red if not. Here is the final build_android.bat with error management.

@echo off
@echo "============================================ COPY RESSOURCES"
rmdir /S /Q "D:\gamedev\Games\swg21\Dev\android\assets"
mkdir "D:\gamedev\Games\swg21\Dev\android\assets"
xcopy "D:\gamedev\Games\swg21\Dev\Resource" "D:\gamedev\Games\swg21\Dev\android\assets" /S /H
del "D:\gamedev\Games\swg21\Dev\android\assets\snd\*.wav"

@echo "============================================ COMPILE NDK"
cd "d:\gamedev\cygwin\bin"
bash --login "./swg21.sh"
IF %ERRORLEVEL% NEQ 0 GOTO FAIL
GOTO SUCCESS
:FAIL
COLOR 40
GOTO END
pause
:SUCCESS

@echo "============================================ COMPILE JDK+Sign"
cd "D:\gamedev\Games\swg21\Dev\android"
call ant release
IF %ERRORLEVEL% NEQ 0 GOTO FAIL

@echo "============================================ COPY FILE TO DROPBOX"
copy "D:\gamedev\Games\swg21\Dev\android\bin\swg21-release.apk" "C:\Users\Win7\Dropbox\temp\swg21.apk"
COLOR 20
:END
pause

Improvements and Conclusion

I’m glad I did this script and don’t understand why I didn’t do it earlier. I now build a new Android apk almost every night.
If you’re working on a team, you might also add source control scripts to get the latest version of your code/resources automatically. Also, my projects path are hardcoded, I should set “swg21″ (the project name) in a command line parameter and use relative paths. I’ll probably do it when I’ll use this script for a second project.
I’ll also do the same thing for iOS when my current project will be closer to release (I’ve read it’s not that trivial to do, we’ll see).
Feel free to share and comment this article here or on twitter.

Sales and Ads Stats of an iOS / Android Game

Saturday, July 14th, 2012

Don’t Feed the Trolls has been released for more than two months now, and revenue is slowing down. I think it’s a good time to look at how much money the game made.

The game and the business model

Don’t Feed the Trolls is an arcade reflex game released on Google Play on May, 3rd, on Apple App Store on May, 17th and on Amazon App Store on May, 31st. The game is free to download and contains ads (AdMob).

On Google Play and iOS, the player can unlock the full version (removes ads, adds two game modes and levels) with a $0.99 in-app. Once purchased, another in-app called “Gold Pack” is available for players to have their name appear golden in the leaderboards. Basically, this “Gold Pack” is made for the players willing to support us with an additionnal purchase of $1.99. I decided to add this “Gold Pack” because I wanted to price the full version $0.99, but I think it’s worth a bit more than that ;) .

On the Amazon App Store, the game is free with ads, there is no in-app and no way to remove the ads. I didn’t implement in-app because Amazon only pays the developers with checks, in US dollars, and French banks charges so much for that that it’s not worth it. Also, it required a lot of code to replace Google Play in-apps and to integrate Amazon SDK. I can’t test on a real device as Kindle Fire are not available in France for now.

The raw stats

Here is the chart with net revenue per day (after Apple/Google’s cut). iPhone/iPad revenue is blue, Android (Google Play and Amazon) revenue is red. Dark colors are sales revenue, light colors are ads revenue (click to enlarge).

sales_stats_dftt_small

If you take some time to look at this chart, it’s pretty easy to read. You can see I added black numbered arrows for specific events, here is the legend:

  1. Release of Don’t Feed the Trolls on Google Play (Android)
  2. Contact many Android-only press/review sites
  3. Release of Don’t Feed the Trolls on the App Store (iOS)
  4. Contact many multiplatform and iOS-only press/review sites
  5. Release of Don’t Feed the Trolls on Amazon App Store (Android, Kindle Fire)
  6. Review on the biggest French android site (FrAndroid)
  7. Contact the press once again with the news : “More than 250,000 trolls slapped! Join the fun”
  8. Game of the Week on the biggest French videogame site (jeuxvideo.com)
  9. App of the day in a French Android app : FreeApps365. This app notifies users every day of the “app of the day”. FreeApps365 had between 100,000 and 500,000 downloads on Google Play (I don’t know the current number of active users). Don’t Feed the Trolls had about 1400 new Android installs this day.
  10. Contact the press for the third time, because of the “Bears Update” (first big content update with new levels)

I got many other mentions and reviews on small sites, but it didn’t really affect downloads (main quotes of reviews are available on the game page).

Some conclusions from this chart:

  • The traffic coming from new players when the game is just released is much bigger on iOS. That probably because of the “New Releases” section in the App Store. There is no such things on Google Play, unfortunately.
  • It’s important to get reviews and articles, especially on big sites. However, download/sales spikes drop quickly once the article leaves the front page.
  • You can’t really see it on this chart, but Amazon traffic is extermely low (you can see the Android revenue stays close to zero the few days after Amazon release).
  • Users of FreeApps365 are really looking for free stuff and didn’t buy many games, but played a lot (big ads spike). Jeuxvideo.com and FrAndroid players on the other hand bought more copies.

 

Total revenue repartition

Here is a pie chart showing a more global repartition of revenue.

sales_stats_pie

This is is even easier to read:

  • Android brought me more money than iOS. It’s obviously because I got covered by Android only sites/articles.
  • Ads brought me more money than sales, both on Android and iOS. However, note that the free version of the game as a lot of content. In fact, I think I shouldn’t have put that much content in the free game. Of course, I can’t tell how reducing free content would have changed this repartition. Also note that without the FreeApps365 mention, sales on Android would bring more money than ads.

It’s also interesting to take into account the number of players. Here is a new pie chart with revenue per active user. I consider an active user a player that played at least one level (or the tutorial) while being connected (he must have an entry in the leaderboards). I ignored Amazon App store for this one but this is negligible, anyway.

sales_stats_pie2

And now, iOS seems to be more valuable.

Conversion Rate

This chart shows the conversion rate of the two in-app purchases, per platform (Full Version is the $0.99 in-app and Gold Pack is the $1.99 one).

sales_stats_cr

Remarks:

  • Before Don’t Feed the Trolls appeared on FreeApps365, the conversion ratio for the Full Version on Android was very close to the iOS one.
  • As the Gold Pack is only displayed to paying players, the ratio of Gold Pack buyers amongs the Full Version buyers is interesting: 10% on iOS, and 4.69% on Android.

 

Ads

I’m using AdMob on both Android and iOS. I noticed very different statistics depending on the platform and thought it would be interesting to share. I’m not showing numbers, the interesting information here is to see the values relative to the other platforms. Once again, keep in mind that my Amazon stats are quite low.

sales_stats_ads

If you are not familiar with these acronyms, here is a definition:

Impressions: Number of different ads displayed to the user.
CTR: Click-Through Ratio : percentage of ads that are clicked
RPM: Revenue per 1000 impressions
RPC: Revenue per click

We already knew that Android ads brough in more money, but you can see in this graphs that the quantity of impression is much higher too. Therefore, the CTR of iOS is a lot more interesting. I didn’t play Don’t Feed the Trolls much with the ads, but could see that iOS ads were sometimes very targeted (links to another game in the app store for example) compared to some of Androids ads (dental surgery for example).

Conclusion

That’s is for the charts (thanks Google Docs) ! I hope you found interesting information in it. Feel free to share your thoughts, remarks and questions in the comments or on twitter !

Don’t Feed the Trolls 1.2 “Bears Update” is now Live!

Thursday, July 5th, 2012

A new version of Don’t Feed the Trolls is now available on iPhone/iPad and Android !

featured_image_update_small

This major update adds nine levels, three characters, and five achievements.
Discover new gameplay with the sleeping bear, the twin bears or the invisible bear and keep slapping the trolls getting in your way. Collect the additional stars and take the opportunity to climb up the leaderboards.

Here is the full changelog:

  • Feature: Three new bears : Sleeping, Twin and Invisible
  • Feature: Nine new levels (three per difficulty)
  • Feature: Five new achievements
  • Tuning: Speedy bear is slightly slower, especially in “Hard”
  • Bugfix: The achievement “Good Start” now unlocks properly when you have exactly 10 stars

Optimizing Graphics Performance on iOS and Android

Tuesday, May 22nd, 2012

The main device is used during the development of Don’t Feed the Trolls is an Acer Iconia Tab A500. It’s quite powerful and I never met performance issues with it.

Of course, I tested the game on many other iOS and Android devices. I was surprised to discover strong performance issues on a HTC Desire.

In this article, I will explain the reasons of these low performances and how I fixed them. I will also give you tips on how to find out where are the potential problems.

Problem 1 : in-game, the game was slower and slower when getting closer to the end of the level

O03. Screenshot - Slap Party Game ModeOf course, the difference at the end of the level is that many bears and trolls have been displayed so the problem probably has to do with that. However, there was never more than 3 or 4 characters visible at the same time.

Also, to avoid memory allocation during gameplay, I pre-allocate all the character sprites used in the level at the start of the level. So the problem was not memory related. Finally, the game code dealing with inactive or invisible characters was doing nearly nothing.

I finally found out the problem is caused by characters that disappeared. They are displayed, but fully transparent. I used a CCFadeOut action to hide the sprites. At the end of the CCFadeOut, the object was still displayed, but with an opacity of 0. An easy fix is to hide the sprite (CCHide action) at the end of the fade out to avoid a useless draw call.

Fix 1 : Make sure you do not have invisible sprites (completely transparent or with very low opacity). Destroy or hide them instead.

Problem 2 : the main menu is very slow

05 - Screenshot - Menu - Achievements ListMy menus have many animated transitions, for instance when you choose the “achievements” menu, the game mode selection screen leaves to the left, while the achievements screen comes from the right. There is also a credits screen, a level selection screen (for the classic mode) and a difficulty selection screen (for the versus mode). All these screens are built once when loading the main menu. They are simply off-screen when not displayed to the player.
The performance problem was therefore obvious: all the offscreen items were slowing down the whole program. I thought cocos2dx or the device itself would not display offscreen items but I was wrong. Simply hiding these items improved the performance greatly. In the achievements list (see screenshot on the left), I hide every line and sprite as soon as it’s out of the screen. It requires specific code but it’s really worthwhile.

Fix 2 : Do not have elements displayed off screen. Remove them from the scene or hide them instead.

Problem 3 : the main menu is slow when the rankings are displayed

07 - Screenshot - Menu - RankingsIn the main menu, when the rankings are displayed (see screenshot on the left), the fps drops heavily. Obviously, this is caused by the quantity of text. Cocos2dx optimizes the texts by using a single OpenGL draw call to display a string, instead of drawing each character one by one. It’s good but not enough in my case. I initially used a simple (and logical) approach and had one CCLabelBMFont per element of the rankings. There are up to 10 lines with 3 elements per line (position, name, score), and two headers. That’s a total of 32 draw calls here, only for texts. I updated the code so that all the rankings texts are now displayed with a single draw call (see below for implementation details). The game is now running smoothly.

Fix 3 : Use as few draw calls as possible by grouping sprites together

How to reduce draw calls with Cocos2d-x?

The easiest way to reduce draw calls is to use a CCSpriteBatchNode. If you have multiple sprites using the same texture, they can be displayed in one call if they share the same CCSpriteBatchNode parent. Hopefully, as I use texture pages, my sprites are nearly all in the same texture (see How to pack your textures). Here are some examples of optimizations I did in Don’t Feed the Trolls:

  • All the elements of the UI (timer bar, troll head, red cross…) now share the same CCSpriteBatchNode (up to five draw calls removed)
  • The bears are displayed with two sprites, the trolls with three sprites. Each character is now displayed as a CCSpriteBatchNode (one or two draw calls removed per character)
  • In the main menu, the rankings background is using the same sprite twice, they now share the same CCSpriteBatchNode (one draw call removed)

For the fonts, the CCLabelBMFont is a CCSpriteBatchNode itself (derivation). However, I have so much text in the rankings that it still slows down the game (Problem 3). I made some code to regroup all the texts of the rankings together under one CCLabelBMFont. As I used different scale, colors, and alignment, it’s not trivial and can’t be done automatically with a single CCLabelBMFont. I decided to have the CCLabelBMFont class positions the letters properly, and then move each letter under a “master label”, and finally deleting the original label. Here is the raw code I used (_mega_label is the node that contains all the text, bmf is the label we want to add to the mega label (temporary object)) :


	// copy the label to mega_label and delete it
	CCArray *children = bmf->getChildren();
	if( children )
	{
		// loop through all characters
		while( children->count() )
		{
			CCNode *ch = (CCNode*)(children->objectAtIndex( 0 ));
			// remove characters from current label (retain it before removing it)
			ch->retain();
			bmf->removeChildAtIndex( 0, true );
			Vector2 char_pos = ch->getPosition();
			// compute proper position taking scale into account
			char_pos.x = char_pos.x*scale + p.x;
			char_pos.y = char_pos.y*scale + p.y;
			ch->setPosition( char_pos );
			ch->setScale( scale );
			// add it to label
			_mega_label->addChild( ch );
			// Don't Feed the Trolls specific : I keep a list of animated sprites
			// (they have there opacity animated)
			// I do it manually instead of using an action
			if( is_local_player )
			{
				// need an animation, add the sprite to a specific list
				_animated_sprites.push_back( (CCSprite*)ch );
			}
			ch->release();
		}
	}
	// free the original label
	bmf->release();

How to find out where to optimize?

You don’t need to optimize everything, just the slow sections of your game. Here is how I found out where to optimize:

  • I display on screen the draw call count. To do that, I hacked into cocos2d-x code and simply added a global counter before each call to glDrawArray or glDrawElements. I used a #define to easily remove this code in released versions of the game. Be careful to ignore the sprites used to display the debug text itself.
  • I also have a function that goes recursively inside a CCNode and count visible/hidden nodes, nodes with low opacity (less than 10) and so on. Very handy to detect items not visible because they are out of the screen or with a very low opacity.
    Here is the code used, adapt it to your needs:

    
    int nb_nodes, nb_visible_nodes, nb_rgba_nodes, nb_not_letters_nodes,
    	nb_not_letters_visible_nodes, nb_low_opacity_nodes;
    
    // recursive function counting
    // please note that I'm using an old version of cocos2d-x, with
    // convertToLabelProtocol and convertToRGBAProtocol: I found the
    // new version with RTTI a terrible idea and reverted it
    void DEBUGCountNodes( CCNode *n, bool parent_visible, bool is_letter )
    {
    	nb_nodes++;
    	bool we_are_visible = n->getIsVisible() && parent_visible;
    	bool father_is_label = is_letter;
    	bool we_are_label = is_letter || (n->convertToLabelProtocol() != NULL);
    
    	if( we_are_visible )
    		nb_visible_nodes++;
    	if( we_are_visible && !father_is_label )
    		nb_not_letters_visible_nodes++;
    	if( !father_is_label )
    		nb_not_letters_nodes++;
    
    	if( n->convertToRGBAProtocol() )
    	{
    		// count low opacity nodes (if below 10/255)
    		if( n->convertToRGBAProtocol()->getOpacity() < 10 && we_are_visible )
    			nb_low_opacity_nodes++;
    		nb_rgba_nodes++;
    	}
     	// recursive part
    	if( n->getChildren() )
    	{
    		for( unsigned int i = 0; i < n->getChildren()->count(); i++ )
    		{
    			DEBUGCountNodes( (CCNode*)(n->getChildren()->objectAtIndex(i)),
    				we_are_visible, we_are_label );
    		}
    	}
    }
    
    // initial function to call, usually with the initial node of your sprite
    // hierarchy (mine is called _main_node)
    string fgGame::DEBUGCocosNodes( CCNode *start )
    {
    	if( start == NULL )
    		start = _main_node;
    	nb_nodes = nb_visible_nodes = nb_rgba_nodes = nb_not_letters_nodes =
    		 nb_not_letters_visible_nodes = nb_low_opacity_nodes = 0;
    	DEBUGCountNodes( start, true, false );
    	char str[256];
    	sprintf( str, "All:%d/%d NoTxt:%d/%d LowOp:%d", nb_visible_nodes, nb_nodes,
    		nb_not_letters_visible_nodes, nb_not_letters_nodes, nb_low_opacity_nodes );
    	return str;
    }
    

The great thing with this logging is that you can run it on the Windows build.

Conclusion

Make sure you test your app on a few less powerful devices. If you keep in mind the tips in this article and display debug information from time to time, you should easily be able to optimize the slowest code of your game.
From my tests, I found out that trying to have a maximum of 30 draw calls is a good way if you want to achieve 50 or 60 frames per second on nearly all medium-end devices. Of course, this is heavily empirical and you’ll have to do you own tests.

I hope this helped, feel free to comment and talk about your optimization techniques in the comments, on twitter or on facebook.

And don’t forget to try and rate Don’t Feed the Trolls (Free download, iTunes, Google Play)!

Don’t Feed the Trolls is available on iPhone / iPad / iPodTouch and Android !

Thursday, May 17th, 2012

Already available since May, 3rd on Android, Don’t Feed the Trolls is now also available on iOS (all devices). It’s a free download, get it now!

Please, feel free to share this news to your friends! ;)

Beta Testing Don’t Feed the Trolls on iOS/Android

Monday, April 2nd, 2012

icon_100Don’t Feed the Trolls on iOS/Android is coming soon! However, before releasing it, I would like to do “live testing” with players around the world to improve the game, and especially:
- Gameplay tuning and difficulty
- Device compatibility
- Game stability and bugs
- Localization errors (English and French)
- Online leaderboards testing

If you are interested to test Don’t Feed the Trolls, please contact me by mail or twitter with your device name. Android games will be sent as an apk (How to Install an APK). On iOS, I will need your UDID to create a specific version, that you will simply download and install with Safari.
Thanks for your help, feel free to share this post!

Gameplay of Don’t Feed the Trolls

Monday, April 2nd, 2012

Here is a description of the gameplay of Don’t Feed the Trolls. If you don’t know it yet, it will be available soon for iPhone/iPad/iPod and Android devices.

banner_small

The gameplay is simple : bears and trolls spawn on the screen, you need to feed the bears and slap the trolls with the touch screen. Ten crazy characters add variety to the gameplay. There are four different game modes:

gm_classic_smallClassic mode:  Successive levels lasting less than a minute, where you need to make a perfect run to get the three stars. The game introduces new characters in each level. There are three unlockable difficulty levels.

gm_100bears_small100 bears mode: Feed 100 bears as fast as possible. You should probably use both hands on this one to make high scores. Be careful, a single troll hides among them!

gm_slapfest_smallSlap Party: Have fun slapping dozens of trolls spawning as fast as possible!

gm_versus_smallVersus: Play with a friend on the same screen. Feed your bears before your opponent while avoiding to feed the trolls.

Each mode has its multiplatform (iOS/Android) leaderboard. You can also unlock 20 achievements. On iOS, achievements and leaderboard are available in Game Center.

How to create a shake action in Cocos2d-x (with source code)

Monday, February 27th, 2012

While working on my next game Don’t Feed the Trolls, I was looking for a “shake effect”. When the player feeds a troll, I want the whole screen to shake to improve visual feedback.
A shake effect is very easy to implement, so I quickly hacked in my code to see if it was un interesting feature. After a quick test on the Android version of the game, I could see it really does improve the game. So I wrote a proper cocos2d-x action to integrate the effect in a clean way. I’m releasing the code here hoping other developers will find it useful for their own games.

The effect

The shake is a small random movement. It can be applied to any cocos2d node (CCNode). In Don’t Feed the Trolls, I applied the effect to my top-most node, therefore the whole screen is shaking.

The action

I derived my CCShake class from CCActionInterval. The action is initialized with two parameters:
- time : the duration of the effect.
- strength : the distance of the shake movement. You can have different strengths in X and Y if you wish.
You create the action with CCShake::actionWithDuration and send it as a parameter of CCNode::runAction.


// Shake node_to_shake for 5 seconds.
node_to_shake->runAction( CCShake::actionWithDuration( 5.0f, 10.0f ) );

When the action is completed, the node is moved back to its starting position.

Source code

The code is free for personal and commercial use. If you plan to use it, feel free to credit me, send me an email and/or follow me on twitter/facebook. This is of course not compulsory.

Header: CCShake.h


#ifndef __SHAKE_H__
#define __SHAKE_H__

#include "CCActionInterval.h"
using namespace cocos2d;

class CCShake : public CCActionInterval
{
	// Code by Francois Guibert
	// Contact: www.frozax.com - http://twitter.com/frozax - www.facebook.com/frozax
public:
	CCShake();

	// Create the action with a time and a strength (same in x and y)
	static CCShake* actionWithDuration(ccTime d, float strength );
	// Create the action with a time and strengths (different in x and y)
	static CCShake* actionWithDuration(ccTime d, float strength_x, float strength_y );
	bool initWithDuration(ccTime d, float strength_x, float strength_y );

	virtual void startWithTarget(CCNode *pTarget);
	virtual void update(ccTime time);
	virtual void stop(void);

protected:
	// Initial position of the shaked node
	float _initial_x, _initial_y;
	// Strength of the action
	float _strength_x, _strength_y;
};

#endif //__SHAKE_H__

Source: CCShake.cpp

// Code by Francois Guibert
// Contact: www.frozax.com - http://twitter.com/frozax - www.facebook.com/frozax
#include "cocos2d.h"
#include "CCShake.h"

// not really useful, but I like clean default constructors
CCShake::CCShake() : _strength_x(0), _strength_y(0), _initial_x(0), _initial_y(0)
{
}

CCShake* CCShake::actionWithDuration( ccTime d, float strength )
{
	// call other construction method with twice the same strength
	return actionWithDuration( d, strength, strength );
}

CCShake* CCShake::actionWithDuration(ccTime duration, float strength_x, float strength_y)
{
	CCShake *p_action = new CCShake();
	p_action->initWithDuration(duration, strength_x, strength_y);
	p_action->autorelease();

	return p_action;
}

bool CCShake::initWithDuration(ccTime duration, float strength_x, float strength_y)
{
	if (CCActionInterval::initWithDuration(duration))
	{
		_strength_x = strength_x;
		_strength_y = strength_y;
		return true;
	}

	return false;
}

// Helper function. I included it here so that you can compile the whole file
// it returns a random value between min and max included
float fgRangeRand( float min, float max )
{
	float rnd = ((float)rand()/(float)RAND_MAX);
	return rnd*(max-min)+min;
}

void CCShake::update(ccTime time)
{
	float randx = fgRangeRand( -_strength_x, _strength_x );
	float randy = fgRangeRand( -_strength_y, _strength_y );

	// move the target to a shaked position
	m_pTarget->setPosition( ccp( randx, randy) );
}

void CCShake::startWithTarget(CCNode *pTarget)
{
	CCActionInterval::startWithTarget( pTarget );

	// save the initial position
	_initial_x = pTarget->getPosition().x;
	_initial_y = pTarget->getPosition().y;
}

void CCShake::stop(void)
{
	// Action is done, reset clip position
	m_pTarget->setPosition( ccp( _initial_x, _initial_y ) );

	CCActionInterval::stop();
}

Possible improvements

This is really a simple class, for a simple effect. You can improve the effect in many ways. For instance, we could animate the strength of the shake over time.

That's it !

Have fun with it, feel free to discuss the source code in the comments, twitter or facebook.

Don’t Feed the Trolls coming to iOS and Android

Monday, February 13th, 2012

It’s now confirmed and official. The next game released by Frozax Games will (hopefully) be a new version of Don’t Feed the Trolls, for iOS and Android. However, it will not be a simple port of the Xbox 360 version.

Are are some of improvements :

  • Improved graphics (see screenshot below)
  • Intuitive touch gameplay (very cool to slap trolls on a touch screen!)
  • More levels
  • Many different game modes (more information coming later)
  • and other stuff that I’ll reveal periodically

Here is a work-in-progress screenshot showing the new art running on the iPhone simulator (click to enlarge).

ios simulator 2010-02-13

The new background is made by Vincent Guibert.

There is no precise release date, the game will be out when it’s done. You can see however that it’s going pretty well. I plan to make a beta because it’s my first mobile game, and I want to test a few gameplay features.

Follow me on facebook or twitter to get more information about Don’t Feed the Trolls and Frozax Games.