Marmalade SDK Tutorial – Actors, Scenes and Cameras Make the World Go Round

This tutorial is part of the Marmalade SDK tutorials collection. To see the tutorials index click here

In our previous tutorial we created an extensible animation system that allowed us to create discrete frame based image animation as well as other types of animations. This week we will continue on our quest to create an easy to use, extensible cross platform 2D game engine. In order to do this effectively we need to get organised and organised we will be. If you just want the code to this tutorial then download it from here.

Ok, so how do we organise things in a 2D engine? What sort of things do we want our 2D engine to do? Here’s a brief list:

  • We want sprites and animations obviously, these we already covered in previous tutorials
  • We want sprite creation / handling to be automated so that we do not have to worry about creating, updating and destroying sprites
  • We want to define specific types of game objects (players, bombs, aliens, pickups etc..) modelled on a single game object type
  • We want scenes that contain our game objects, managing their life times and updates
  • We want cameras that we can move around in our scene to view different parts of the scene.
  • We want our game objects to recognise when they collide with each other and react to each other

To manage all of the above we are going to create a Camera, Actor, Scene (CAS) system.

Cameras, Actors and Scenes

The camera, actor and scene system (CAS) constitutes the logical implementation of our game engine. The scene represents our finite gaming world, whilst actors represent our individual game objects that live within our gaming world. The scene manages all of our actors for us, taking care of updating them and deleting them when they are no longer needed. The camera represents a view into the gaming world that can be moved around, rotated and scaled to view different parts of the world.

CIwGameActor – Our game objects are really just actors on a stage

Ok, we will begin by taking a look at the CIwGameActor class:

class CIwGameActor { protected: // Properties CIwGameScene* Scene; // Scene that actor lives in bool Used; // Used is used when actors pooled to reduce memory fragmentation bool Managed; // Marks this actor as being managed by another object so we do not delete it unsigned int NameHash; // Name of Actor (stored as an hash for speed) int Type; // Type of Actor (use to distinguish beteeen different actor types) CIwFVec2 OriginalPosition; // Original position of actor in the scene (when actor was first spawned) CIwFVec2 Position; // Current position of actor in the scene CIwFVec2 Velocity; // Current velocity of actor CIwFVec2 VelocityDamping; // Dampens the velocity float OriginalAngle; // Original angle in scene (when first spawned) float Angle; // Orientation in scene (degrees) float AngularVelocity; // Angular velocity float AngularVelocityDamping; // Angular velocity damping float Scale; // Scale CIwColour Colour; // Colour bool IsActive; // Active state of actor bool IsVisible; // Visible state of actor bool IsCollidable; // Collidable state of actor CIwGameSprite* Visual; // Visual element that represents the actor CIwGameAnimManager* VisualAnimManager; // Visuals animation manager, used to control the actors visual componen animations int CollisionSize; // Size of collision area CIwRect CollisionRect; // Spherical collision size float PreviousAngle; // Previous updates angle CIwFVec2 PreviousPosition; // Previous updates position public: void setUsed(bool in_use) { Used = in_use; } bool isUsed() const { return Used; } void setManaged(bool managed) { Managed = managed; } bool isManaged() const { return Managed; } void setScene(CIwGameScene* scene) { Scene = scene; } CIwGameScene* getScene() { return Scene; } void setName(const char* name) { NameHash = IwHashString(name); } unsigned int getNameHash() { return NameHash; } void setType(int type) { Type = type; } int getType() const { return Type; } void setOriginalPosition(float x, float y) { OriginalPosition.x = x; OriginalPosition.y = y; } CIwFVec2 getOriginalPosition() { return OriginalPosition; } void setPosition(float x, float y) { Position.x = x; Position.y = y; } CIwFVec2 getPosition() { return Position; } void setOriginalAngle(float angle) { OriginalAngle = angle; } float getOriginalAngle() { return OriginalAngle; } void setAngle(float angle) { Angle = angle; } float getAngle() { return Angle; } void setVelocity(float x, float y) { Velocity.x = x; Velocity.y = y; } CIwFVec2 getVelocity() { return Velocity; } void setVelocityDamping(float x, float y) { VelocityDamping.x = x; VelocityDamping.y = y; } void setAngularVelocity(float velocity) { AngularVelocity = velocity; } float getAngularVelocity() const { return AngularVelocity; } void setAngularVelocityDamping(float damping) { AngularVelocityDamping = damping; } void setScale(float scale) { Scale = scale; } float getScale() const { return Scale; } void setColour(CIwColour& colour) { Colour = colour; } CIwColour getColour() const { return Colour; } void setActive(bool active) { IsActive = active; } bool isActive() const { return IsActive; } void setVisible(bool visible) { IsVisible = visible; } bool isVisible() const { return IsVisible; } void setCollidable(bool collidable) { IsCollidable = collidable; } bool isCollidable() const { return IsCollidable; } void getVisual(CIwGameSprite* visual) { Visual = visual; } CIwGameSprite* getVisual() { return Visual; } void setVisualAnimManager(CIwGameAnimManager* anim_manager) { VisualAnimManager = anim_manager; } CIwGameAnimManager* getVisualAnimManager() { return VisualAnimManager; } void setCollisionRect(CIwRect& rect); CIwRect getCollisionRect() const { return CollisionRect; } int getCollisionSize() const { return CollisionSize; } void setPreviousPosition(float x, float y) { PreviousPosition.x = x; PreviousPosition.y = y; } CIwFVec2 getPreviousPosition() const { return PreviousPosition; } void setPreviousAngle(float angle) { PreviousAngle = angle; } float getPreviousAngle() const { return PreviousAngle; } // Properties end CIwGameActor() : Used(false), Managed(false), Scene(NULL) { Reset(); } virtual ~CIwGameActor(); // Reset the actor (used by memory pooling systems to save actor re-allocation, usually called after re-allocation to reset the object to a default state) virtual void Reset(); // Update the actor (called by the scene every frame) virtual bool Update(float dt); // Update the visual that represents this actor on screen virtual bool UpdateVisual(); // Actors are responsible for carrying out there own collision checks. Called after all actor updates to check and resolve any collisions virtual void ResolveCollisions() = 0; // NotifyCollision is called by another actor when it collides with this actor virtual void NotifyCollision(CIwGameActor* other) = 0; // Call to see if this actor was tapped by the user virtual bool CheckIfTapped(); // Checks to see if another actor is colliding with this actor bool CheckCollision(CIwGameActor* other); };

Hmm, I agree, its a bit on the BIG side, but if you look carefully our CIwGameActor class provides a lot of functionality built in, which in the long run will save us lots of coding time. Again, you never create a direct instance of this class as it is abstract, you dervice your own different actor types from CIwGameActor.

We handle a lot of functionality with this base class including:

  • Position, orientation, scale, angular velocity, velocity damping and angular velocity damping – Physical attributes of our actor
  • Visibility state, active state, collide-able state – Used to hide, disable and mark as collide-able objects
  • Object type identifier, object name (used to search for specific types of objects or named objects). These are very useful as they allow you to create actors and forget about them, no need to store a pointer to them to reference them later, you simply ask the scene to find the object by name or type to access it again.
  • Visual, colour and animation manager – We will use these variables to give our object a visual representation in our world
  • Collision size and collision rectangle are used for collision detection

Note that eventually we will be replacing the physical components in this class with the Box2D physics engine.

I would like to point out a few important methods in this class:

  • Update() – When you implement your own actor types you override this method to provide the implementation of your game object specific behaviour. For example, if you create a player actor then you may check and move the player, maybe fire of different animations / sound effects. The default implementation of Update() will update the basic physics for the actor, any attached playing animations as well as add the actor to the collision check list if it is collision enabled. You should call CIwGameActor::Update() in your own Update() implementation, if you want to keep this functionality.
  • UpdateVisual() – You do not generally need to override and provide your own implementation of this method as this method will automatically update the actors associated visual for you.
  • ResolveCollisions() – When the scene has finished calling all of its actor updates it will then call ResolveCollisions() on each of the actors. You provide the implementation of this method to check for collisions with other actors. We implement collision checking this way as it allows us to optimise which collision checks to make. For example, lets say we are creating the old game Asteroids. The scene consists of 10 asteroids, 10 bullets and our ship. Our ship actor only needs to check for collisions with the asteroids and not the bullets or the ship.
  • NotifyCollision() – When an actor collides with another actor we need some mechanism for letting the other actor know that we have collided with them. When an actor collides with this actor it will call its NotifyCollision() method to let it know, this gives the actor a chance to respond to the collision event
  • CheckIfTapped() – Whilst this method is not currently implemented it will eventually allow us to check and see if the actor was tapped by the user. This is good for allowing the user to interact with our actors
  • CheckCollision() – Helper method for checking if two actors bounding circles overlap

One important note about Actors is there coordinate system. As far as our scene is concerned, the worlds centre is the the middle of the scene (0, 0), which corresponds to the centre of the screen for a scene that has not been moved.

CIwGameActorImage – An image based actor helper class

I suspect that many of you will want to simply get up and running quickly with your game and not have to worry about deriving your own actor class. With that in mind I created an image based actor that allows you to quickly set up a basic image based actor, complete with a sprite atlas, a base animation and a size. Lets take a quick look at the code in that class as I thin it will prove helpful when it comes to you designing your own actors:

bool CIwGameActorImage::Init(CIwGameScene* scene, CIw2DImage* image, CIwGameAnimImage* anim, int width, int height) { // Reset the actor CIwGameActor::Reset(); // Set the scene Scene = scene; // Create sprite if (image != NULL) { CIwGameBitmapSprite* sprite = new CIwGameBitmapSprite(); if (sprite == NULL) return false; // Set sprite image sprite->setImage(image); sprite->setDestSize(width, height); // Set sprite as visual Visual = sprite; // Add sprite to the sprite manager so it can be managed and drawn Scene->getSpriteManager()->addSprite(sprite); } // Create an animation manager and add the animation to it if (anim != NULL) { VisualAnimManager = new CIwGameAnimManager(); VisualAnimManager->setUpdateAll(false); if (VisualAnimManager == NULL) return false; VisualAnimManager->addAnimation(anim); // Set the first animation in the animation manager as the current animation VisualAnimManager->setCurrentAnimation(0); } return true; }

Our Init() method is pretty simple, it resets the actors internal data to default, creates a bitmapped sprite visual from the image and actor size then creates an animation manager and adds our default animation to it.

bool CIwGameActorImage::UpdateVisual() { if (CIwGameActor::UpdateVisual()) { // Update the sprite if (VisualAnimManager != NULL) { // Get the animations current image frame data and copy it to the bitmapped sprite CIwGameAnimImage* anim = (CIwGameAnimImage*)VisualAnimManager->getAnimation(0); if (Visual != NULL) ((CIwGameBitmapSprite*)Visual)->setSrcRect(anim->getCurrentFrameData()); } return true; } return false; }

Our UpdateVisual() method simply moves the image animation frame data to our sprite to update its image.

Unfortunately you will still need to derive your own actor from CIwGameActorImage() in order to create an actor object

CIwGameScene – A place for actors to play

The scene is the place where we put actors. When you add an actor to a scene the scene will take care of calling game logic update and visual update methods and building a list of potential colliding actors, as well as cleaning up the actors when the game is finished.
The scene also takes care of updating the camera and fitting our game across different sized screens with different aspect ratios. Look as the scene as the driving force that manages much of our game processes for us, so we can get on with coding up cool actors and other game logic.Lets take a quick look at the CIwGameScene class:

class CIwGameScene { public: // Public access to actor iteration typedef CIwList::iterator _Iterator; _Iterator begin() { return Actors.begin(); } _Iterator end() { return Actors.end(); } // Properties protected: CIwGameSpriteManager* SpriteManager; // Manages sprites for the whole scene CIwGameAnimFrameManager* AnimFrameManager; // Manages the allocation and clean up of animation frames unsigned int NameHash; // Hashed name of this scene CIwVec2 ScreenSize; // Native screen size CIwVec2 VirtualSize; // The virtual size is not the actual size of the scene. but a static pretend size that we can use to render to without having to cater for different sized displays CIwMat2D VirtualTransform; // Virtual transform is used to scale, translate and rotate scene to fit different display sizes and orientations CIwMat2D Transform; // Scene transform CIwList Actors; // Collection of scene actors CIwRect Extents; // Extents of scenes world CIwGameCamera* Camera; // Current camera CIwGameActor** Collidables; // List of collidable objects built this frame int MaxCollidables; // Maximum allowed collidables int NextFreeCollidable; // Points to next free slot in sollidables list pool public: CIwGameSpriteManager* getSpriteManager() { return SpriteManager; } // Manages sprites for the whole scene CIwGameAnimFrameManager* getAnimFrameManager() { return AnimFrameManager; } // Manages the creation and clean up of animation frames void setName(const char* name) { NameHash = IwHashString(name); } unsigned int getNameHash() { return NameHash; } CIwVec2 getScreenSize() const { return ScreenSize; } CIwVec2 getVirtualSize() const { return VirtualSize; } void setVirtualTransform(int required_width, int required_height, float angle, bool fix_aspect = false, bool lock_width = false); CIwMat2D& getVirtualTransform() { return VirtualTransform; } CIwMat2D& getTransform() { return Transform; } void addActor(CIwGameActor *actor); void removeActor(CIwGameActor* actor); void removeActor(unsigned int name_hash); CIwGameActor* findActor(unsigned int name_hash); CIwGameActor* findActor(int type); void clearActors(); void setExtents(int x, int y, int w, int h) { Extents.x = x; Extents.y = y; Extents.w = w; Extents.h = h; } CIwRect getExtents() const { return Extents; } void setCamera(CIwGameCamera* camera) { Camera = camera; } CIwGameCamera* getCamera() { return Camera; } bool addCollideable(CIwGameActor* actor); CIwGameActor** getCollidables() { return Collidables; } int getTotalCollidables() const { return NextFreeCollidable; } // Properties end private: public: CIwGameScene() : Collidables(NULL), SpriteManager(NULL), AnimFrameManager(NULL), NextFreeCollidable(0), Camera(NULL), MaxCollidables(0) {} virtual ~CIwGameScene(); // After creating the scene, call Init() to initialise it, passing the maximum number of actors that you expect can collide virtual int Init(int max_collidables = 128); // Update() will update the scene and all of its contained actors virtual void Update(float dt); // Draw() will draw all of the scenes actors virtual void Draw(); // Event handlers };

Yep, I know, its another biggy, but again it supports lots of cool functionality such as:

  • Handles all of our actors
  • Handles our camera
  • Fits our game to any sized screen / any aspect ratio using a virtual size display
  • Tracks potential colliders
  • Manages sprites and animation frames

You will be happy to know that you do not need to derive you own scene from CIwGameScene() and you will generally instantiate and work with a version of this class directly. Our scene class does not however need a little setting up initially. Heres asome basic code on how to set up a scene:

CIwGameScene* game_scene = new CIwGameScene(); game_scene->Init(); game_scene->setVirtualTransform(VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT, 0, true, false);

I think at this point I need to explain something about the virtual screen system that I use to ease the pain of cross platform development

Using a Virtual Screen Size to Target Any Sized Screen

There are quite a few different solutions knocking around that solve the problem of targeting our game at a variety of different screen resolutions, including:

  • Scale to fit – This is a very simple scaling of the scene to match the display resolution. This is quick and simple but your game can appear stretched or squashed on displays that have a different aspect ratio to your game aspect ratio
  • Bordered – Another simple system that displays your game at its native resolution but with a border around it to fill the space that your game doesn’t cover. I don’t like this method as you are giving up too much screen real-estate
  • Unlimited screen size – This method is quite complex and involves rendering enough stuff on screen at a 1:1 pixel resolution to cover the entire screen. This disadvantage (and advantage, depends how much time you have on your hands) of using this method is that you would need to display a much larger area of the gaming world on a higher resolution display than on a lower resolution display.
  • Virtual screen – This method uses a pretend screen size that best fits many resolutions (800 x 512 / 512 x 800 is a good choice). Your game renders everything as though it is rendering to the virtual size and not the actual phones / tablets native screen size. You later scale and translate the virtual canvas to fit onto the native phones screen resolution.

We could use any of these methods in our game, but I am going to use a virtual canvas because it is the most convenient. Our CIwGameScene class has a method called setVirtualTransform() which will set this up for us, so that all of our actors will render to the virtual screen size. Heres how to use the method:

void CIwGameScene::setVirtualTransform(int required_width, int required_height, float angle, bool fix_aspect, bool lock_width)

  • required_width, required_height – This is the width and height we would like to use for our virtual screen
  • fix_aspect – Tells the scene to fix the aspect ratio of the scene to match the native screen aspect ratio
  • lock_width – Tells the scene to fix eth aspect ratio based on the width of the display instead of the height

CIwGameCamera – Our View Into the Gaming World

Many games can get away with simply one visible screen of information (such as Asteroids, Space Invaders, Pac-man etc..), but other types of games such as platformers, sports games, strategy games etc.. require the ability to move around the gaming world in some fashion. This is usually accomplished by using a camera that can move our point of view within the world. CIwGameScene supports the attachment of a camera to allow us to move our view around a larger virtual world. Lets take a quick look at the CIwGameCamera class:

class CIwGameCamera { public: // Properties protected: unsigned int NameHash; // Hashed name of this camera CIwMat2D Transform; // The combined camera transform CIwFVec2 Position; // Position of view within scene float Scale; // Cameras scale float Angle; // Cameras angle bool TransformDirty; // Marks camera transform needs rebuilding public: void setName(const char* name) { NameHash = IwHashString(name); } unsigned int getNameHash() { return NameHash; } CIwMat2D& getTransform() { return Transform; } void setPosition(float x, float y) { Position.x = x; Position.y = y; TransformDirty = true; } CIwFVec2 getPosition() const { return Position; } void setScale(float scale) { Scale = scale; TransformDirty = true; } float getScale() const { return Scale; } void setAngle(float angle) { Angle = angle; TransformDirty = true; } float getAngle() const { return Angle; } void forceTransformDirty() { TransformDirty = true; } bool isTransformDirty() const { return TransformDirty; } // Properties end private: public: CIwGameCamera() : Position(0, 0), Scale(1.0f), Angle(0), TransformDirty(true) {} virtual ~CIwGameCamera() {} // Updates the camera virtual void Update(); // Event handlers };

Ah much better, nice and short. As you can see the camera class is quite simple, supporting position, rotation and scaling of the view. To use a camera we simply create one and attach it to the Scene, the scene will then follow the camera around. To see different areas of the game world we simply move the camera around and all of our actors will move along with it.

Cool, I’m now done with explaining the new classes. I’ve been battling with trying to keep this article short and to the point, but alas I don’t think its quite happening for me.

What’s changed in IwGame Code

Marmalade SDK - Actor, Scene Camera Example
Marmalade SDK - Actor, Scene Camera Example


I will be honest, A LOT has changed since the previous article and I will try my best to walk through most of it; this is the main problem with an engine that’s  in-development.

Firstly I have had to make quite a few changes to our previous classes including:

  • CIwGameAnim – CIwGameAnimFrameManager now handles the life time of animation frames and not the separate animation classes themselves
  • CIwGameAnimFrameManager – Added the ability to retrieve allocated animation frames
  • CIwGameAnimManager – setCurrentAnimation() never actually set the current animation (oops, fixed)
  • CIwGameBitmapSprite – Source rectangle can now be set from a CIwGameAnimImageFrame (helper method just saves some typing)
  • CInput – This class has been renamed to CIwGameInput to fit in with the frameworks naming conventions. CIwGameInput is now a singleton and not declared as a global variable (I’m not generally a fan of global variables and prefer to use singletons for systems that there will only ever be one instance of). If you do not know what a singleton is then think of it as a global instance of a class.

Now onto the changes to Main.cpp. Note that I won’t be going into minor details such as “Oh I included these header files”.

We now accesss input using a singleton, here we have to create the IwGameInput singleton and then initialise it:

// Initialise the input system CIwGameInput::Create(); IW_GAME_INPUT->Init();

Note that IW_GAME_INPUT is just a macro that calls CIwGameInput::getInstance() (I find it more readable to use the macro)

Next, we create and initialise a scene then create a camera and attach that to the scene

// Create a scene CIwGameScene* game_scene = new CIwGameScene(); game_scene->Init(); game_scene->setVirtualTransform(VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT, 0, true, false); // Create a camera and attach it to the scene CIwGameCamera* game_camera = new CIwGameCamera(); game_scene->setCamera(game_camera);

Next, we allocate a bunch of image animation frames for our manic face animation. Take note that we now allocate them through the game scenes animation manager. This ensures that the game scene later cleans them up for us.

// Allocate animation frames for our player CIwGameAnimImageFrame* anim_frames = game_scene->getAnimFrameManager()->allocImageFrames(8, 36, 40, 0, 0, 512, 40, 512);

Within our main loop we check for the player tapping the screen and if they do we explode 10 sprites into the scene at the tapped position:

if (IW_GAME_INPUT->getTouchCount() > 0) { if (!PrevTouched) { // Get tapped position in our virtual screen space CIwFVec2 pos = game_scene->ScreenToVirtual(IW_GAME_INPUT->getTouch(0)->x, IW_GAME_INPUT->getTouch(0)->y); // Create 10 player actors for (int t = 0; t < 10; t++) { // Create and set up our face animation CIwGameAnimImage* face_anim = new CIwGameAnimImage(); face_anim->setFrameData(anim_frames, 8); face_anim->setLooped(-1); face_anim->setPlaybackSpeed(0.2f); face_anim->Start(); // Create player actor ActorPlayer* player = new ActorPlayer(); player->Init(game_scene, sprites_image, face_anim, 36, 40); player->setName("Player"); player->setPosition(pos.x, pos.y); // Add player actor to the scene game_scene->addActor(player); } } PrevTouched = true; } else PrevTouched = false;

Note that because we are now dealing with a virtual screen resolution and not the actual native screen resolution, our tap coordinates need converting to virtual screen coordinates. We achieve that using the ScreenToVirtual() method of the CIwGameScene class.

Also note that we still have to create our face_anim animation, but this time we pass it to the ActorPlayer Init() method, so that the actor / scene can take of its management.

Next we update and draw the scene:

// Update the scene game_scene->Update(1.0f); // Draw the scene game_scene->Draw();

Lastly we clean-up the camera, scene and input system:

// Safely clean up the camera if (game_camera != NULL) delete game_camera; // Safely cleanup game scene if (game_scene != NULL) delete game_scene; // Shut down the input system IW_GAME_INPUT->Release(); CIwGameInput::Destroy();

ActorPlayer our First Derived Actor

ActorPlayer is our very first user defined CIwGameActor based actor and because we derived it from CIwGameActorImage (and in turn CIwGameActor) we get all of the useful functionality defined in those classes.

The only parts of our ActorPlayer that’s worth drawing out are the Init() and Update() methods:

bool ActorPlayer::Init(CIwGameScene* scene, CIw2DImage* image, CIwGameAnimImage* anim, int width, int height) { CIwGameActorImage::Init(scene, image, anim, width, height); FadeTimer.setDuration(1000); Velocity.x = IwRandMinMax(-100, 100) / 20.0f; Velocity.y = IwRandMinMax(-100, 100) / 20.0f; AngularVelocity = IwRandMinMax(-100, 100) / 20.0f; return true; }

Our Init() method calls the base CIwGameActorImage::Init() method to initialise the base CIwGameActorImage part of the actor. We then set up a fade timer and random velocities for position and spin.

bool ActorPlayer::Update(float dt) { // If fade timer has timed out then delete this actor if (FadeTimer.HasTimedOut()) { return false; // Returning false tells the scene that we need to be removed from the scene } // Calculate our opacity from time left on fade timer int opacity = FadeTimer.GetTimeLeft() / 2; if (opacity > 255) opacity = 255; Colour.a = opacity; return CIwGameActorImage::Update(dt); }

Our Update() method is called every game loop by the scene system, so keep in mind that this code will be called every single game frame. Firstly we check to see if the fade timer has timed out and if it has then we return false to the the scene system (this causes the actor to be removed from the scene / game) after the scene has finished updating all actors.

We then calculate the opacity of our actor from the time left on the fade timer which causes the actor to fade out of existence.

And that’s about it for this article, hope that most of your managed to stay awake, long drawn out technical stuff can send the best of us to sleep, especially if read on a few hours sleep, which is usually the case for us programmer types. The source code that accompanies this article can be downloaded from here

I’m quite happy with this blog as it marks the start of a real usable cross platform game engine that we can now build upon. In our next tutorial we are going to cover upgrading the engine to include some very basic collision detection and response whilst building a small game using the engine to show working collision. We will also cover handling frame rate variations and putting some audio in there. Hopefully I will get the time to do that this weekend.

That’s it for now and don’t forget HTML 5 is evil! (Just kidding, I got a book on it the other day and it looks quite good, think that I may use it to spruce up my blog)

Marmalade SDK News – Marmalade SDK 5.1.9 now available for download

A new minor update of the Marmalade SDK has been released. Here are the changes:

  • IwGx: Added [GX] DisableFBOSurface icf option to allow disabling this functionality on devices which do not or poorly support FBO surfaces.
  • Android: Fix s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR) having incorrect behaviour after user closes soft-keyboard with back key.
  • Android: Fix for s3eWebView extension crashing in certain circumstances.

Jusr a few fixes really. The most exiting thing about this release is the version number 5.1.9, that’s the version prior to the big 5.2 update that many of us Marmaladians are eagerly awaiting 🙂

Beginning of the end for Nintendo?

Just read here that Nintendo are to reveal a pre-tax loss of ¥100 billion (£821 million), which is a lot of money even for Nintendo. With the recent flop of 3DS and developers turning away from Nintendo DS / Wii because of high production costs, bad sales and the terrible WiiWare and DSiWare platforms, is there much future left for Nintendo? Nintendo are also suffering at the hands of smart phones and tablets such the iPhone, iPad and Android, with the insanity driven sea of free and $0.99 games and apps (termed frapp-mentality) taking over, people do not want to pay $20-$40 for a hand held game these days,

How can Nintendo survive? Well they can go the way of console hardware manufacturers of the past such as Sega and sell / rework old intellectual properties / develop games across platforms. They could even embrace the Android platform and create their own handheld based / phone / tablet on the technology, offering their own premium Nintendo apps channel.

Who knows, is this the beginning of the end of the much loved Nintendo as a console developer / manufacturer or do Nintendo have something up their sleeves that will blow us away like the Nintendo Wii originally did? Maybe some crazy cool virtual reality console that you control with your mind!? I guess we will have to just wait and see.

Hats off to Nintendo and good luck to them.

Bada App and Game Marketing – Playing the Samsung Apps Store for Bada to Boost Sales

Hello fellow Samsung Bada app developers! We know exactly what it’s like to drop a few products onto Samsung Apps store and see them teeter around 5-10 sales per day at $0.99.

We have two products up on the Samsung App Store:

BattleBallz Chaos (a game)
Funky Cam 3D (a camera app)

You may be asking questions such as, how can I breath life into my app / game sales? How do I get my apps and games into Samsung’s top 10? How do I get enough exposure to make my app or game stand out amongst the mass of products already on the Samsung App Store?

The simple answer is to be generous and give it away for free! You may be thinking that I have lost my mind at this point, but I will show you why I haven’t.

Think of giving your app away for free as a temporary promotion tool. You set your app free until users have downloaded the magical number of downloads then you cancel your promotion and put your price back to its original price. This is a guaranteed way of boosting your apps sales and increasing visibility temporarily, shooting your app or game up in the charts.

We have done a fair bit of “price playing” since we launched our products on the Samsung Apps store and it appears that we need to give away around 4000-5000 copies to get into the top 10 over a period of two days. This free promotion will give us a sales boost for around 7-10 days, where we will be selling 5-10x as many products at $1.99.

When to make your product free on Samsung Apps? We saw our greatest downloads on a Monday (triple the number of downloads on any other day). Just be hopeful that products such as Angry Birds or Cut the Rope aren’t on promotion at the same time 🙂

The great thing about a free promotion is that the Samsung Bada press will usually pick up on it and advertise your product as going free on their web sites, which is added exposure.

News from Pocketeers

We finally scrounged a little free time to update our company web site with some of our latest developments over at http://www.pocketeers.co.uk

Pocketgamer.biz featured some of my mental ramblings with regards to the Marmalade SDK over on their site today, so I’m pleased as punch.

I also found myself watching some of RIM’s Devcon 2011 (live web cast), which was very interesting. During the advert break I noticed an ad for the Blackberry Playbook showing a user playing a variety of games on it and low and behold our BattleBallz Chaos was on there! 🙂

Hello Marmalade – Introduction to the Marmalade SDK – The ultimate cross platform SDK for smart phones and tablets

This tutorial is part of the Marmalade SDK tutorials collection. To see the tutorials index click here

So you are a smart phone, tablet, smart TV or desktop developer (or at least want to be) and you want to have your next hit game or app run across a huge range of smart phones and tablets. Well, you have come to the right place to find out how to do just that.

No matter whether you are a professional games developer, part time hobbyist coder or the technical director of a large corporation researching how to support you work force across a huge range of varied phones and tablets, the basic principles remain the same. By choosing to develop your products across multiple platforms:

  • You benefit from a much wider audience for your apps and games
  • You save a lot of money and time on development, testing and updating
  • You can perform updates to your existing apps quickly and easily
  • You can share the same unified C / C++ code base across all devices and platforms
  • No need to learn (or hire professionals that know) multiple languages, UI’s or SDK’s
  • Regularly updated SDK with new platforms and features
  • Some of the smaller app stores offer increased visibility and more stable long term sales

And by choosing the Marmalade SDK you also get:

  • A FREE license/li>
  • Amazing support, including the apps program and device loan program to aid testing
  • A simulator that lets you test across an unlimited set of screen resolutions and simulated access to Accelerometer, GPS, Camera, Audio, Multi-touch screen, SMS, Compass and more
  • Test actual ARM code without even deploying to an ARM based device
  • Support for iOS specific features such as App Store Billing, iAd, Game Center etc..
  • Support for Android specific features such as Android Market Billing
  • Access to a large collection of open API’s such as Box2D, AdMob, Flurry, Chipmunk,SVG, Python, LUA and tonnes of other cool stuff (Full list available at http://github.com/marmalade)

Marmalade is also partnered with the likes of Shiva3D, Scoreloop, Tapjoy, Raknet and many others, so you know this is an SDK that’s here to stay

Ok so what platforms does Marmalade actually support? The list to date is as follows:

  • iPhone, iPod Touch and iPad
  • Android
  • Blackberry Playbook
  • Blackberry 10
  • Windows
  • Windows Phone 8
  • OSX
  • Tizen
  • Roku

I know what you are thinking, can I really write my code once and run it across all of these platforms? The straight answer is “absolutely!” as we at Pocketeers have proven. We have already released BattleBallz Chaos (Arcade action game) across iOS, Android, Bada and Blackberry Playbook using the Marmalade SDK, as well as Funky Cam 3D (a fun photography app) across iOS, Android and Bada.

Ok, so if you can write your code once and deploy to so many platforms then why is your BattleBallz Chaos not available on the likes of Symbian or webOS? The simple answer is that some of those platform markets are not currently where we want to go for a variety of reasons, but none of those reasons relate to the Marmalade SDK. We may choose to support them in the future and we may not.

Righty ho, you’ve decided that you quite like the sound of this Marmalade SDK and you’re considering saving yourself a boat load of time and money developing your cross platform games and apps, but what does code look like with this SDK?

Well here’s a basic game loop:

#include “IwGx.h”

int main()
{
    // Initialise Marmalade graphics system
    IwGxInit();

    // Main Game Loop
    while (!s3eDeviceCheckQuitRequest())
    {
        // Clear the screen and depth buffer
        IwGxClear(IW_GX_COLOUR_BUFFER_F | IW_GX_DEPTH_BUFFER_F);

        // Update my awesome game
        PleaseUpdateMyGame();

        // Render my awesome games view
        RenderMyGameViewThankyou();

        // Flush graphics system
        IwGxFlush();

        // Display the rendered frame
        IwGxSwapBuffers();

        // Yield to the operating system
        s3eDeviceYield(0);
    }

    // Shut down Marmalade graphics system
    IwGxTerminate();

    return 0;
}

You will find that the graphical system in Marmalade is similar to Open GL, which for me makes the SDK very simple to use. All other sub systems are equally as easy to use for example:

To create a texture from a bitmap file and upload it to the GPU:

CIwTexture* texture = new CIwTexture();
texture->LoadFromFile(“AwesomeSpriteAtlas.png”)
texture->Upload();

As you can see the code is ultra simple and very easy to use but most of all “cross platform compatible!”. Imagine having to do this on iOS using XCode / Objective C and then again using Java on Android and then again using Flash on Playbook, the list goes on.

So unless you enjoy self punishment, lots of extra work and the pain of tracking the same bugs across multiple SDK’s, languages and platforms, I suggest you take a short trip over to Marmalade’s SDK home page at http://www.madewithmarmalade.com. Take a look at the SDK, its features, read some tutorials and even sneak a peek in the forums (I bite but not many of the other developers do!)

Over the coming weeks / months I will be writing a number of tutorials covering various aspects of the Marmalade SDK, associated tools and extensions, so keep an eye out.

Marmalade SDK and Blackberry Playbook – From Setup and Deployment to App World Submission

The latest version of the marvellous Marmalade SDK 5.1.3 has recently hit our development machines. Whats so special about 5.1.3 you ask? Well for starters you can now deploy your smart phone and tablet apps and games to the awesome Blackberry Playbook. If you haven’t had the chance to tinker with one of these beauties then I suggest you go and have a play because they are fantastic tablets. Amazon are selling them right now here for 16GB version and here for 64GB version

Ok you read this far and thought, “hmm, what the hell is the Marmalade SDK fool?”, sounds like something you would spread on toast and not actually use to make ground breaking cross platform games and apps. For those developers that have been asleep for the last couple of years or maybe just missed the name change, the Marmalade SDK is the newly named AirPlay SDK created by the boffins over at IdeaWorks. The marmalade SDK is basically an awesome system that allows developers to develop apps and games using a single unified API for a whole host of platforms including Apple iPhone, iPad, Android phones & tablets, Samsung Bada, Blackberry Playbook, Web OS, Symbian, Windows Mobile, Windows, Mac and others. How do they do that you may ask, well don’t ask me! take a trip over to http://www.madewithmarmalade.com and take a look

Ok, shameless plug for my favourite SDK of all time out of the way, now on with the article

We have recently just ported one of our games “BattleBallz Chaos” to the Blackberry Playbook platform and had it published in record time (for our company at least). Within 24 hours we went from receiving our Blackberry Playbook test tablet and our unified Android, iOS, Bada code base to “on the App World store!” For those interested you can check out BattleBallz Chaos here and more info about our other versions for iPhone, iPad, Android, Bada and Windows Phone 7 is at http://www.battleballz.com

BattleBallz Chaos Blackberry Playbook Screen Shot
BattleBallz Chaos in action on the Blackberry Playbook

You are probably here because you are pulling your hair out trying to accomplish one of the following:

  • Deploy a debug build to an actual Blackberry Playbook tablet
  • Having trouble getting your build ready for submission to RIM’s Blackberry App World store
  • Need to know the splash screen, icon formats and sizes for a Blackberry Playbook build
  • Other random issues with Marmalade or Blackberry Playbook deployment or submissions

Well for whatever reason I hope this article can help you in some small way, now on with the article

Preparing your system

1. Grab a copy of the Blackberry Web Works SDK from http://us.blackberry.com/developers/tablet/webworks.jsp. Note that you will also have some other tools to install which are listed on that same page, just follow the instructions
2. Install the SDK to your development machine as specified

You may be wondering why you would need to install the HTML5 SDK when you are deploying a native application. The reason is that you need the binary tools that are located in this SDK. Note that the native SDK is Beta at the moment and is only available by asking Blackberry directly for access to the beta program at http://03268fe.netsolhost.com/bbbeta/

Set up your PC to allow signing with the Blackberry signing server: (Only has to be done once)

3. Go to Blackberrys online code signing keys request tool at https://www.blackberry.com/SignedKeys/, fill in the information and submit,. You will be emailed 2 registration files that look something like this (DONT FORGET YOUR PIN!):

  • client-RDK-195133201.csj – This is for the signing process (RBK)
  • client-PBDT-195133201.csj – This is for the debug token creation process (PBDT)

NOTE: It may take a few days to get the registration files so apply for them immediately

4. Now lets actually do the set-up process

* Copy the registration files from step 3 into a folder (lets call it ‘Playbook’)
* Open up a command prompt and change to the ‘Playbook’ folder you just created
* Run the following commands at the command prompt:

"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-keytool" -genkeypair -keystore sigtool.p12 –storepass {your_password} -dname "cn={your_company_name}" -alias author
"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-signer" -csksetup -cskpass {your_password}
"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-signer" -register –csjpin {your_pin} -cskpass {your_password} client-RDK-195133201.csj

{your_password} – Choose a password that you are going to remember
{your_company_name} – Company name as specified when you requested the registration files in step 3
{your_pin} – The pin you created when you requested the registration files in step 3
client-RDK-195133201.csj – Change this to the name of the RDK CSJ file that you received in your registration files email in step 2

NOTE: The location where the blackberry-keytool and blackberry-signer will probably be different depending on which SDK you are using and where you installed it

Set up your PC to enable generation of debug tokens (Only has to be done once)

5. Open up a command prompt and change to the ‘Playbook’ folder created in step 4 then enter the following at the command prompt

"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-debugtokenrequest.bat" -register -cskpass {your_password} -csjpin {your_pin} client-PBDT-195133201.csj

{your_password} – The same password that you chose in step 4
{your_pin} – The pin you created when you requested the registration files in step 3
client-PBDT-195133201.csj – Change this to the name of the PBDT CSJ file that you received in your registration files email in step 2

Generate a debug token to allow deployment of debug builds to the Blackberry Playbook tablet

6. Open up a command prompt and change to the ‘Playbook’ folder created in step 4 then enter the following at the command prompt

"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-debugtokenrequest" -cskpass {your_password} -keystore sigtool.p12 -storepass {your_password} -deviceId 0x{device_id} name_of_your_debug_token.bar

{your_password} – The same password that you chose in step 4
{device_id} – Your Blackberry Playbooks device ID
name_of_your_debug_token.bar – Note that you should not use any funny characters or spaces in this name, best bet is to name it something like companynamedebugtoken.bar

NOTE: To find your Blackberry Playbooks device id do the following:
* Tap the settings icon in the top right hand corner of the playbooks screen to bring up settings
* Select “’About ‘ item on the left hand side menu
* In the drop down box to the right selected “’Hardware’
* The ‘PIN’ number shown is your device ID

Install the debug token to the Blackberry Playbook tablet

7. if you haven’t already done so then ensure that you have connected your Playbook to your local Wi-Fi network. Go to Settings->Wi-Fi and set it up here.
8. Go to settings->About then select ‘Network’ from the drop down list to the right which displays info about your network. Now note down the IP address of the Playbook (something like 192.168.1.2)
9. Enable “Development Mode” on your Blackberry Playbook as follows:

* Go to Settings->Security->Development Mode
* Slide the development mode slider to “On”
* You will be asked to enter a password (for simplicity use the same password as you use for logging into your Playbook)
* Select “Upload debug token” button

And finally to install the debug token to the Playbook, open up a command prompt and change to the ‘Playbook’ folder created in step 4 then enter the following at the command prompt to install the debug token to the Playbook

"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-deploy" -installDebugToken name_of_your_debug_token.bar –device {ip_address} –password {playbook_password}

name_of_your_debug_token.bar is the name of your debug token that you create in step 6
{ip_address} – The IP address that you noted down in step 8
{playbook_password} – This is the security password that you have set for your Blackberry Playbook (The one you type in when you log into your Playbook)

Ok, the hard bit is out of the way, take a breather and go for a coffee, next part is deploying via the Marmalade SDK, which is thankfully a much easier process

Deploying your Marmalade SDK app to the Blackberry Playbook tablet

There are a few things you need to do on the Marmalade side in order to get your build ready for deployment to the Blackberry Playbook:

10. MKB project file modifications

* If you want to appear as the author for your app then you need to add the following to the Playbook deployment section of your MKB:

playbook-author='Your company name'

* So that RIM can identify you as the real author of the app they need to know your author ID. The line in your MKB will look something like this:

playbook-authorid='gBACAgDE-PVmaTowNV2UQzp61q32'

The aiuthor-id is however a little elusive. The easiest way to find it is to rename the “name_of_your_debug_token.bar” file that you generated in step 6 as a zip file “name_of_your_debug_token.zip” for example. Open the zip file and extract the MANIFEST.MF file. open this file in a text editor and fiind the field called “”Package-Author-Id” the value for this field is the authorid you need to supply to the Marmalade build system

* To set the Splash Screen and icon use the following two MKB commands:

splashscreen=PlaybookSplash.png
icon=PlaybookIcon.png

The splash screen and icons will be scaled to the correct sizes, but I recommend choosing a large sized splash screen that matches the 1024 x 600 pixel aspect ratio screen and 86 x 86 pixel icon (rounded corners and transparency are allowed in the icon)

Ok, now you have this in place, compile and run your ARM release build. When the Marmalade deployment tool runs and gets to the final stage of deployment you need to enter the following details:

* Device hostname (or IP address) – Enter the IP address that you noted down in step 8
* Device password – Enter your playbook security password (The one you type in when you log into your Playbook)

If you selected Package and Install in the previous Marmalade deployment step then you should find your apps shiny icon on the Playbooks screen (under games category most likely)

Ok, you can now deploy your build to an actual Blackberry Playbook, but what about preparing your BAR file for submission to Blackberry App World, we shall cover that next

Preparing your app for submission to the Blackberry App World Store

In order to submit your app to Blackberry for App World approval you will need to sign your BAR file:

11. Edit the file located at “\Marmalade\5.1\s3e\deploy\plugins\qnx\MANIFEST.MF” and change the line that reads “Application-Development-Mode: true” to “Application-Development-Mode: false”. Remember to change it back to true when you are deploying development builds
12. Open up a command prompt and change to the folder where you MKB is located (lets say for example ‘e:\Apps\CoolGame’)
13. Copy the file ‘sigtool.p12’ from the ‘Playbook’ folder that you created in step 4 into the folder specified in step 12
14. Run the following commands at the command prompt: (when resigning the same build you only need to perform steps 12 and 14)

"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-signer" -verbose -cskpass {your_password} -keystore sigtool.p12 -storepass {your_password} build_coolgame_vc10\deployments\Blackberry\playbook\release\CoolGame.bar RDK
"E:\Program Files\Research In Motion\BlackBerry WebWorks SDK for TabletOS 2.1.0.6\bbwp\blackberry-tablet-sdk\bin\blackberry-signer" -keystore sigtool.p12 -storepass {your_password} build_coolgame_vc10\deployments\Blackberry\playbook\release\CoolGame.bar author

{your_password} – The same password that you chose in step 4
build_coolgame_vc10\deployments\Blackberry\playbook\release\CoolGame.bar – You need to replace this section with the relative path to your .BAR file for your app

You now have a signed BAR file that you can submit to Blackberry App World for approval! Good luck with your submission and good luck with sales!

A Few Notes

* You can choose a separate CSK password and store password if you like to increase security
* Remember to replace the path to the Blackberry tools with the correct path for your Blackberry SDK install
* Our app only took around 16 hours to get approval but we noticed that the number of new apps appearing around our time of submission were few and far between so it could take longer
* Ensure you have a working internet connection throughout the whole process as the Blackberry tools will need to query various external servers
* If you are having trouble with deploying your debug build then ensure that a) Your Blackberry Playbooks IP address has not changed and b) Your debug token has not expired (they have a very short life span)
* If you would like your app to be classified in a category other than “’games’ you will need to change the application category line “Application-Category: core.games” located in the file “\Marmalade\5.1\s3e\deploy\plugins\qnx\MANIFEST.MF”

Confirming that your app has been signed

To confirm that you app has been signed by both the RIM signing authority and yourself open your BAR file as a zip file and check the META-INF folder. This folder should contain 5 files:

* AUTHOR.EC
* AUTHOR.SF
* MANIFEST.MF
* RDK.EC
* RDK.SF

If any are missing then something went wrong and you need to sign again. Note that if you receive an error saying something along the lines of “already signed” then change your version number, rebuild and re-sign

Android Apps – The Hard Sell? – Comparison of Android App Stores Included

Selling your wares on the Android platform is what some would call “a waste of time” and to be honest I would be very tempted to agree with them. Why would this be the case you may ask? In this article I will attempt to answer that question as well as put forward a comparison of a number of Android app stores, so you know which are worth the effort and which are waste of your time.

In this article I am going to use our latest app “Funky Cam 3D” for Android phones and tablets (http://www.funkycam3d.co.uk) as a frame of reference.

Our company Pocketeers Limited (http://www.pocketeers.co.uk) released its latest Android app “Funky Cam 3D” across a number of Android app stores a few weeks ago. To date we have had a grand total of 14 sales, YES, you did read that right “14” sales. The very same app on iOS has sold 20x that amount in half the time and 10x as many on Samsung Bada in just 2 days

Ok, so we took the rather disappointing sales on the chin and came up with a cunning plan to get the app selling somehow. Our first idea was to drop the price to free for a few days in an attempt to increase the apps popularity with users. Unfortunately the Android Market does not allow developers to change an app from free to paid, which means as soon as a developer changes their app to free they cannot change it back to paid without deleting the app and re-launching it under a new name.

So as an alternative we decided to release a free ad-supported version of Funky Cam 3D. Going on how badly our app was selling we were surprised when many thousands of Android users downloaded our app across various app stores and directly from our web site.

Ok, now the “pain in the ass” bit. Submitting apps to the various app stores is a difficult and time consuming process, a process that will bring you close to tears. Each developer portal has its very own submissions system as well as required art work sizes and formats. Unlike when you submit an app to Apple for certification you find that you spend days on the task of submitting your apps information to the various app stores out there. Why not just submit the app to the Android Market you ask, surely the Android market would offer the greatest exposure? Maybe the following figures will clear this up:

Android Download Statistics for Funky Cam 3D

Our own web site – Over 15,000 downloads (we posted our APK link to various public forums and warez forums)
Appia – 3880 copies
Android Market – 2506 copies
SlideMe – 1198 copies
Mobiles24 – 701 copies
Mobango – 549 copies
Mikandi – 143 copies
AndroidPit – 134 copies
GetJar – 48 copies
Handster – 19 copies
Soc.io mall – 0 copies

As you can see from the above list we have some clear winners and some clear losers. Notable points:

* It would appear that one of the best ways to market free apps is from your own web site coupled with aggressive marketing.
* Appia actually beat the Android Market by a substantial margin, which surprised us. In case you are wondering Appia supply apps to various partners such as Handango, Pocketgear and Mobile2day
* SlideMe figures were a big surprise, we did not expect such figures from what we thought as a minor portal
* Our biggest surprise above all was how badly our app has performed on GetJar, which is supposedly one of the largest app distributors on the planet (we just have no explanation)
* Our greatest downloads came from warez forums. We expected a lot of downloads from this source but were knocked back by just how many we got

So above all else, what did we learn from our little Android app experiment? Well, we learnt that Android users don’t like to pay for apps but will download free apps in droves! A mentality we have coined “frap-mentality”. We also learnt that Ad supported apps do not offer a sufficient return even if downloaded in the 10’s of thousands. Our ad revenues are enough to pay for a cheap meal at the local public house (maybe a subject for a new blog)

If you are considering building a business around developing apps or gaming products for the Android platform then make sure that it is your 2nd choice of platform. Use a cross platform development system such as the Marmalade SDK (http://www.madewithmarmalade.com), this way you can re-target Android quite easily without significant investment in Java or the Android SDK.

You can download Funky Cam 3D from the Android market at:

Funky Cam 3D on the Android Market and
Free version of Funky Cam 3D on the Android Market for those that like shiny new Ads

Update 30th August 2011

Quick download figures update to this post:

Our own web site – Over 17,000 downloads (slowed substantially)
Appia – 13526 copies (massive increase)
Android Market – 4188 copies (pleasant increase)
Mobango – 2623 copies (huge jump)
SlideMe – 1503 copies (up 50%)
Mobiles24 – 942 copies (up a little)
AndroidPit – 214 copies (nearly doubled)
Mikandi – 174 copies (up a little)
GetJar – 154 copies (almost tripled but figures are still terrible)
Handster – 34 copies (good increase but still low figures)
Soc.io mall – 0 copies (Hmm, are these guys alive?)

Update 9th October 2011

Quick download figures update to this post:

Appia – 73665 downloads (massive increase)
Our own web site – 22,000 (slowed considerably)
SlideMe – 12306 downloads (massive increase)
Android Market – 11070 downloads (huge increase)
Mobango – 5042 downloads (good increase)
AndroidFreeware – 3189 downloads (new addition)
1Mobile – 1955 downloads (new addition)
Mobiles24 – 1673 downloads (respectable increase)
AndroidPit – 441 downloads (nearly doubled)
GetJar – 366 downloads (good increase, but I thought that this app store was supposed to be the largest free app store out there?)
Mikandi – 274 downloads (up a little)
Handster – 96 downloads (good increase but still low figures)
Soc.io mall – 1 download (woohoo at last!)

Downloads have nearly doubled in most app Android stores , but some app stores are clearly flying ahead!

Update 16th October 2011

Another quick download figures update to this post:

Appia – 93014 downloads (no stopping Appia)
Our own web site – 22,000 (stopped tracking, its too much effort)
SlideMe – 14260 downloads (slight jump)
Android Market – 12233 downloads (slight jump)
Mobango – 5109 downloads (slight increase)
AndroidFreeware – 3317 downloads (slight increase)
1Mobile – 1955 downloads
Mobiles24 – 1770 downloads (slight increase)
AndroidPit – 473 downloads (slight increase)
GetJar – 400 downloads (up a bit)
Mikandi – 284 downloads (up a little)
Amazon App Store – 128 downloads over 2-3 months (This is the paid version but Amazon have had it free that long it counts as free for this article)
Handster – 103 downloads (tiny increase but still low figures)
Fasmicro – 34 downloads (new addition, around 2 months data)
Appoke – 2 downloads (new addition, live 6 days)
Mobireach – 2 download (new addition, 4 weeks data)
Soc.io mall – 2 downloads (we got another download :))
CNET – 1 download (new addition, 5 weeks of data)

Update 6th November 2011

Another quick download figures update to this post:

Appia –  148390 downloads
SlideMe – 20286 downloads
Android Market – 15276 downloads
Mobango – 5393 downloads
AndroidFreeware – 3616 downloads
1Mobile – Removed as 1Mobile no longer show download stats
Mobiles24 – 1975 downloads
GetJar – 724 downloads (in contrast one of our very old J2ME mobile game DEMOS  has been downloaded 3.759 times in the same period, making GetJar very much still a Java ME app store)
AndroidPit – 549 downloads
Mikandi – 312 downloads
Amazon App Store – 170 downloads
Handster – 126 downloads
Fasmicro – 38 downloads
Mobireach – 17 downloads
Appoke – 14 downloads
Soc.io mall – 8 downloads
CNET – 1 download

Other Android Developer Downloads / Sales Statistics

I will list here any other developers Android sales / downloads statistics that I come across:

Ziggys Android Download Statistics at ZIggy’s Games

If you would like a link to your Android download or even sales statistics posting here then let me know